Як зупинити / # / в браузері з реактор-роутером?


103

Будь-який спосіб запобігти появі /#/в адресному рядку веб-переглядача під час використання react-router? Це з ReactJS. тобто Переходи по посиланнях , щоб перейти на новий маршрут шоу localhost:3000/#/або localhost:3000/#/about. Залежно від маршруту.


1
Це пов'язано з використанням HashHistoryiso BrowserHistory. Дивіться також це питання, де я даю багато довідкової інформації з цього приводу.
Stijn de Witt

Відповіді:


78

Для версій 1, 2 і 3 реактора-маршрутизатора правильним способом встановлення маршруту до схеми відображення URL-адрес є передача реалізації історії в historyпараметр <Router>. З документації з історії :

У двох словах, історія знає, як слухати адресний рядок веб-переглядача для змін та аналізує URL-адресу на об'єкт розташування, який маршрутизатор може використовувати для узгодження маршрутів та надання правильного набору компонентів.

Версії 2 і 3

У реактор-маршрутизаторі 2 і 3 ваш код конфігурації маршруту буде виглядати приблизно так:

import { browserHistory } from 'react-router'
ReactDOM.render (( 
 <Router history={browserHistory} >
   ...
 </Router> 
), document.body);

Версія 1

У версії 1.x ви замість цього використовуватимете наступне:

import createBrowserHistory from 'history/lib/createBrowserHistory'
ReactDOM.render (( 
  <Router history={createBrowserHistory()} >
   ...
  </Router> 
), document.body);

Джерело: Посібник з оновлення версії 2.0

Версія 4

Для майбутньої версії 4 реактора-маршрутизатора синтаксис сильно змінився, і його потрібно використовувати BrowserRouterяк кореневий тег маршрутизатора.

import BrowserRouter from 'react-router/BrowserRouter'
ReactDOM.render (( 
  <BrowserRouter>
   ...
 <BrowserRouter> 
), document.body);

Джерело Реагувати Router Version 4 Docs


6
Зауважте, що historyце окремий пакет, який потрібно буде встановити.
Ян Клімо

4
Вони змінили browserHistoryв v2.x: import { browserHistory } from 'react-router' <Router history={browserHistory} />Перевірте посібник з оновлення реакцій-маршрутизатора
pistou

Дякую @pistou, я оновив відповідь до версії 2.0!
Адам Браун

1
Бо hashHistoryчи є спосіб врешті позбутися цього параму запиту? http://localhost:8080/#/dashboard?_k=yqwtyu
Con Antonakos

2
@Matt Це працює, але вимагає підтримки на сервері. Це тому, що коли ви оновлюєтесь, ви потрапляєте на сервер із URL-адресою із контуром.
Штійн де Вітт

40
Router.run(routes, Router.HistoryLocation, function (Handler) {
  React.render(<Handler/>, document.body);
});

Для поточної версії 0.11 і вперед, вам потрібно додати Router.HistoryLocationдо Router.run(). <Routes>тепер застарілі. Дивіться Посібник з оновлення для реалізації програми 0.12.x HistoryLocation.


1
це повністю зруйнувало мою програму. схоже, їх поточна реалізація баггі?
ninjaneer

2
@Ninja, можливо, опублікує нове запитання з точними номерами версій для реагування та реагування маршрутизатора, невдалого коду та отриманих помилок.
pxwise

@Chet Схоже, що документи-реактори маршрутизатора перемістилися. Оновлене посилання на єдину посилання для HistoryLocation, знайдене в Посібнику з оновлення.
pxwise

21

Якщо вам не потрібно підтримувати IE8, ви можете використовувати історію браузера, а реакційний роутер використовуватиме window.pushStateзамість того, щоб встановлювати хеш.

Як саме це зробити, залежить від використовуваної версії React Router:


Дякую @ ben-alpert, я зараз це розумію.
Giant Elk

1
Я додав, <Routes location="history">що все працює добре, поки ви не оновите браузер, коли ви знаходитесь на маршруті, тобто localhost:3000/aboutтоді я отримаю помилку 404. Це очікується, я використовую python -m SimpleHTTPServer 3000?
Гігантський лось

5
Потрібно переконатися, що ваш сервер може обробляти URL-адресу стану натискання. У цьому випадку це, ймовірно, означає, що вам просто потрібно переконатися, що те, що обслуговує ваш додаток, завжди надсилає всі URL-адреси, які він отримує, до того ж кореня. Таким чином, це /aboutфактично завантажує вашу кореневу сторінку /. Інакше ваш сервер намагається шукати маршрут, який відповідає, /aboutі нічого не знаходить (404). Я особисто не використовую python, але ви зазвичай знаходите вручну маршрут /*або /.*-> /працює - або це може бути щось, що називається html5ModeURL-адресами в налаштуваннях вашого сервера.
Водій Майка

3
IE9 не підтримує pushState - так що це справді "Якщо вам не потрібно підтримувати IE9", правильно? Я хотів би помилитися
Цимен

1
Це посилання github - це сторінка, яку зараз не знайдено.
k00k

9

Ви можете реально використовувати .htaccess для цього. Браузеру зазвичай потрібен роздільник рядка запиту ?або #визначити, звідки починається рядок запиту та закінчуються контури каталогів. Кінцевий результат, якого ми хочемо, - www.mysite.com/dir Тому нам потрібно вирішити проблему, перш ніж веб-сервер шукатиме каталог, який, на його думку, ми просили /dir. Отже, ми розміщуємо .htaccessфайл у корені проекту.

    # Setting up apache options
    AddDefaultCharset utf-8
    Options +FollowSymlinks -MultiViews -Indexes
    RewriteEngine on

    # Setting up apache options (Godaddy specific)
    #DirectoryIndex index.php
    #RewriteBase /


    # Defining the rewrite rules
    RewriteCond %{SCRIPT_FILENAME} !-d
    RewriteCond %{SCRIPT_FILENAME} !-f

    RewriteRule ^.*$ ./index.html

Потім ви отримуєте параметри запиту з ім'ям window.location.pathname

Тоді ви можете уникнути використання реакційних маршрутів, якщо хочете, а також просто маніпулювати URL-адресою та історією веб-переглядача, якщо хочете. Сподіваюся, це допоможе комусь ...


Який еквівалент для Jboss?
Рагаван

5

Встановіть пакет історії

npm install history --save

Далі імпортуйте створення історії та useBasename з історії

import { createHistory, useBasename } from 'history';
...
const history = useBasename(createHistory)({
  basename: '/root' 
});

якщо URL-адреса вашої програми www.example.com/myApp, то / root має бути / myApp.

передайте змінну історії в маршрутизатор

render((
  <Router history={history}>
    ...
  </Router>
), document.getElementById('example'));

Тепер для всіх ваших тегів Link додайте "/" перед усіма шляхами.

<Link to="/somewhere">somewhere</Link>

Натхнення рішення прийшло з прикладу React-Router, який, на жаль, не був належним чином задокументований у їх API.


для цього потрібен сервер вузлів? Я намагаюся досягти одного і того ж стилю URL-адреси, але лише за допомогою клієнта. Це можливо?
Себастіалонсо

1
ні, вам не потрібен сервер вузлів. Насправді я бігаю по бекенду з джанго. Але вам, певно, потрібен вузол для інструментів.
Мокс

1
Гаразд, я спробував такий підхід. Коли я натискаю F5, я отримую лише "Не знайдено". Чи можна в цій історії з цим боротися?
Себастіалонсо

якщо ви не знайдете, це повертається сервером. це означає, що шаблон URL-адреси не є частиною маршрутизатора реагування.
Мокс

1
Так, прочитавши трохи більше, все стало зрозуміло. Я закінчив це з хеш-історією без ключів.
Себастіалонсо

3

Ще один спосіб впоратися з тим, що відображатиметься після хешу (тому якщо ви не використовуєте pushState!) - створити власну CustomLocation та завантажити її під час створення ReactRouter.

Для прикладу, якщо ви хочете, щоб URL-адреса хешбангу (так з #!) Відповідав специфікаціям Google для сканування, ви можете створити файл HashbangLocation.js, який переважно копіює оригінальний HashLocation, наприклад:

'use strict';

var LocationActions = require('../../node_modules/react-router/lib/actions/LocationActions');
var History = require('../../node_modules/react-router/lib/History');

var _listeners = [];
var _isListening = false;
var _actionType;

function notifyChange(type) {
  if (type === LocationActions.PUSH) History.length += 1;

  var change = {
    path: HashbangLocation.getCurrentPath(),
    type: type
  };

  _listeners.forEach(function (listener) {
    listener.call(HashbangLocation, change);
  });
}

function slashToHashbang(path) {
  return "!" + path.replace(/^\//, '');
}

function ensureSlash() {

  var path = HashbangLocation.getCurrentPath();
  if (path.charAt(0) === '/') {
    return true;
  }HashbangLocation.replace('/' + path);

  return false;
}

function onHashChange() {
  if (ensureSlash()) {
    // If we don't have an _actionType then all we know is the hash
    // changed. It was probably caused by the user clicking the Back
    // button, but may have also been the Forward button or manual
    // manipulation. So just guess 'pop'.
    var curActionType = _actionType;
    _actionType = null;
    notifyChange(curActionType || LocationActions.POP);
  }
}

/**
 * A Location that uses `window.location.hash`.
 */
var HashbangLocation = {

  addChangeListener: function addChangeListener(listener) {
    _listeners.push(listener);

    // Do this BEFORE listening for hashchange.
    ensureSlash();

    if (!_isListening) {
      if (window.addEventListener) {
        window.addEventListener('hashchange', onHashChange, false);
      } else {
        window.attachEvent('onhashchange', onHashChange);
      }

      _isListening = true;
    }
  },

  removeChangeListener: function removeChangeListener(listener) {
    _listeners = _listeners.filter(function (l) {
      return l !== listener;
    });

    if (_listeners.length === 0) {
      if (window.removeEventListener) {
        window.removeEventListener('hashchange', onHashChange, false);
      } else {
        window.removeEvent('onhashchange', onHashChange);
      }

      _isListening = false;
    }
  },

  push: function push(path) {
    _actionType = LocationActions.PUSH;
    window.location.hash = slashToHashbang(path);
  },

  replace: function replace(path) {
    _actionType = LocationActions.REPLACE;
    window.location.replace(window.location.pathname + window.location.search + '#' + slashToHashbang(path));
  },

  pop: function pop() {
    _actionType = LocationActions.POP;
    History.back();
  },

  getCurrentPath: function getCurrentPath() {
    return decodeURI(
    // We can't use window.location.hash here because it's not
    // consistent across browsers - Firefox will pre-decode it!
    "/" + (window.location.href.split('#!')[1] || ''));
  },

  toString: function toString() {
    return '<HashbangLocation>';
  }

};

module.exports = HashbangLocation;

Зверніть увагу на функцію slashToHashbang .

Тоді вам доведеться робити

ReactRouter.create({location: HashbangLocation})

І це все :-)

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.