I have non-SPA server-side application with React application that is limited to current page, /some/static/page. The application has <base href="/"> in <head> on all pages and relies on it, this cannot be changed.
Here is basic example with React 16, React Router 4 and <HashRouter>:
export class App extends React.Component {
render() {
return (
<HashRouter>
<div>
<Route exact path="/" component={Root} />
</div>
</HashRouter>
);
}
}
All routes can be disabled for testing purposes, but this doesn't change the behaviour.
Here is create-react-app project that shows the problem. The steps to replicate it are:
npm inpm start- navigate to
http://localhost:3000/some/static/page
HashRouter is clearly affected by <base>. It redirects from /some/static/page to /#/ on initialization, while I expect it to be /some/static/page#/ or /some/static/page/#/ (works as intended only in IE 11).
There's a quick splash of Root component before it redirects to /#/.
It redirects to /foo/#/ in case of <base href="/foo">, and it redirects to /some/static/page/#/ when <base> tag is removed.
The problem affects Chrome and Firefox (recent versions) but not Internet Explorer (IE 11).
Why is <HashRouter> affected by <base>? It's used here exactly because it isn't supposed to affect location path, only hash.
How can this be fixed?
Actually this from
history. If you see their code, they use justcreateHashHistoryand setchildren. So it equivalent with this:It will show same issue you have. Then if you change
historycode like this:then your problem will gone but definitely not use
hash. So the problem not fromHashRouterbut fromhistory.Because this come from
history, let's see this thread. After read that thread, we can take conclusion this is feature fromhistory.so, if you set
<base href="/">, because you are usinghash(#), when browser loaded ( actually aftercomponentDidMount) it will appendhash(#) in your casesome/static/page=>some/static/page+/=>/+#/=>/#/. You can check incomponentDidMountsetdebuggerto catch before append route.SOLUTION
simply, just remove element
<base href>or don't useHashRouter.If still need but want avoid from specific
component, just put this beforeclass:UPDATE
since you want to keep
basetag to keep persist link and usehashrouter, here the close solution I think.1. Set tag
baseto empty.put that code in
Appcomponent (root wrap component) to call once.2. When
componentDidMountset it backusing timeout to wait react done render virtual dom.
This is very close, I think (have test it). Because you are using
hashrouter, link from index html will safe (not override by react but keep bybasetag). Also it work with css link<link rel="stylesheet" href="styles.css">as well.