Hashrouter маршрутизатора React перенаправляет на url-адрес тега
у меня есть серверное приложение без SPA с приложением React, которое ограничено текущей страницей,/some/static/page
. приложение <base href="/">
на <head>
на всех страницах и полагается на него, это не может быть изменено.
вот основной пример с React 16, React Router 4 и <HashRouter>
:
export class App extends React.Component {
render() {
return (
<HashRouter>
<div>
<Route exact path="/" component={Root} />
</div>
</HashRouter>
);
}
}
все маршруты могут быть отключены для целей тестирования, но это не меняет поведение.
здесь create-react-app
проект это показывает проблему. Шаги для его репликации:
npm i
npm start
- перейти к
http://localhost:3000/some/static/page
HashRouter явно зависит от <base>
. Он перенаправляет из /some/static/page
to /#/
при инициализации, в то время как я ожидаю, что это будет /some/static/page#/
или /some/static/page/#/
(работает по назначению только в IE 11).
есть быстрый всплеск Root
компонент перед перенаправлением на /#/
.
это перенаправляет на /foo/#/
в случае <base href="/foo">
, и он перенаправляет на /some/static/page/#/
, когда <base>
тег удаляется.
проблема затрагивает Chrome и Firefox (последние версии), но не Internet Explorer (IE 11).
почему <HashRouter>
влияет <base>
? Он используется здесь именно потому, что он не должен влиять на путь местоположения, только хэш.
как это можно исправить?
5 ответов
на самом деле это из history
. Если вы видите код, они используют только createHashHistory
и set children
. Так что это эквивалентно этому:
import React from 'react';
import { Route, Router } from 'react-router-dom';
import { createHashHistory } from 'history';
const Root = () => <div>Root route</div>;
export default class App extends React.Component {
history = createHashHistory({
basename: "", // The base URL of the app (see below)
hashType: "slash", // The hash type to use (see below)
// A function to use to confirm navigation with the user (see below)
getUserConfirmation: (message, callback) => callback(window.confirm(message)),
});
render() {
return (
<Router history={this.history}>
<div>Router
<Route exact path="/" component={Root} />
</div>
</Router>
);
}
}
он покажет ту же проблему, что и у вас. Тогда, если вы измените history
такой код:
import {createBrowserHistory } from 'history';
...
history = createBrowserHistory({
basename: "", // The base URL of the app (see below)
forceRefresh: false, // Set true to force full page refreshes
keyLength: 6, // The length of location.key
// A function to use to confirm navigation with the user (see below)
getUserConfirmation: (message, callback) => callback(window.confirm(message))
});
тогда ваша проблема исчезнет, но определенно не использовать hash
. Так что проблема не от
HashRouter
а от history
.
потому что это происходит от history
давайте посмотрим этот нить. После прочтения этой темы мы можем сделать вывод, что это характеристика С history
.
так, если вы установите <base href="/">
, потому что вы используете hash
( # ), когда браузер загружен ( на самом деле после componentDidMount
) он будет добавлять hash
(#) в вашем случае some/static/page
=>some/static/page
+ /
=>/
+ #/
=>/#/
. Вы можете зарегистрироваться componentDidMount
set debugger
поймать перед добавлением маршрута.
решение
просто, просто удалите элемент <base href>
или не использовать HashRouter
.
если еще нужно, но хотите, чтобы избежать определенных component
, просто поставьте это перед class
:
const base = document.querySelector("base");
base.setAttribute('href', '');
обновление
так как вы хотите сохранить base
тег, чтобы сохранить ссылку persist и использовать hash
маршрутизатор, вот близкое решение, я думаю.
1. Установить тег base
пустое.
const base = document.querySelector('base');
base.setAttribute('href', '');
ставим этот код в App
component (root wrap component) для вызова однажды.
2. Когда componentDidMount
установить его обратно
componentDidMount() {
setTimeout(() => {
base.setAttribute('href', '/');
}, 1000);
}
используя тайм-аут для ожидания реакции, выполните рендеринг виртуального dom.
это очень близко, я думаю (проверить его). Потому что вы используете hash
маршрутизатор, ссылка из индекса html будет безопасной (не переопределять react, но держать base
tag). Также он работает с css link <link rel="stylesheet" href="styles.css">
как хорошо.
Если вы видите https://developer.mozilla.org/en-US/docs/Web/HTML/Element/base#Hint, он говорит, что с помощью <base>
даже с # target URLs ожидается поведение.
и далее https://reacttraining.com/react-router/web/api/HashRouter он говорит в разделе basename: string: правильно отформатированное базовое имя должно иметь начальную косую черту, но нет Слэша.
возможно, вам следует определить другое базовое имя на HashRouter
элемент или удалить косую черту из <base>
Я закончил HOC, который просто применяет исправление, описанное в ответ :
function withBaseFix(HashRouter) {
return class extends React.Component {
constructor() {
super();
this.baseElement = document.querySelector('base');
if (this.baseElement) {
this.baseHref = this.baseElement.getAttribute('href');
this.baseElement.setAttribute('href', '');
}
}
render() {
return <HashRouter {...this.props}>{this.props.children}</HashRouter>;
}
componentDidMount() {
if (this.baseElement)
this.baseElement.setAttribute('href', this.baseHref);
}
}
};
const FixedHashRouter = withBaseFix(HashRouter);
...
<FixedHashRouter>
<div>
<Route exact path="/" component={Root} />
</div>
</FixedHashRouter>
...
Это вопрос history
пакета. Он даже разрешен, пожалуйста, посмотрите на это pr
в качестве временного исправления я предлагаю вам просто указать эту ветку в package.json
"dependencies": {
...
"history": "git://github.com/amuzalevskiy/history.git",
...
}
и как только исправление будет объединено в исходную ветвь-верните это обратно к фиксированному основному модулю npm
по поводу РЕПО:
Я только что сделал npm run build
на решение microbouji и commited результат, так как невозможно использовать оригинал репозиторий не работает publish
скрипт
ваше замечание о HashRouter
и <base>
тег является правильным. Я подал вопрос о различиях в браузерах здесь:https://github.com/ReactTraining/history/issues/574 и соответствующий PR с исправлением здесь:https://github.com/ReactTraining/history/pull/577
в то же время, я не уверен обо всех маршрутизации вам нужно, но если приложение react живет полностью под /some/static/page/
, вы можете вероятно сделать его работать с:
<BrowserRouter basename="/some/static/page">
.