我的非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>
);
}
}
出于测试目的,可以禁用所有路线,但这不会改变行为。
显示问题的 Here is create-react-app
project。复制它的步骤是:
npm i
npm start
http://localhost:3000/some/static/page
HashRouter明显受<base>
影响。它在初始化时从/some/static/page
重定向到/#/
,而我希望它是/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>
影响?它在这里使用的确是因为它不应该影响位置路径,只有哈希。
如何解决这个问题?
答案 0 :(得分:2)
实际上来自history
。如果您看到their code,则他们只使用createHashHistory
并设置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
,让我们看看thread。阅读完该主题后,我们可以从history
得出结论 feature 。
所以,如果你设置<base href="/">
,因为你正在使用hash
(#),当浏览器加载时(实际上在componentDidMount
之后)它将附加hash
(#)在您的情况下some/static/page
=&gt; some/static/page
+ /
=&gt; /
+ #/
=&gt; /#/
。您可以在追加路线之前签入componentDidMount
设置debugger
来抓住。
简单地说,只需删除元素<base href>
或不使用HashRouter
。
如果仍然需要但希望避免使用特定component
,请将其放在class
之前:
const base = document.querySelector("base");
base.setAttribute('href', '');
因为您希望保留base
标记以保持持久链接并使用hash
路由器,所以我认为这是一个非常接近的解决方案。
<强> 1。将代码base
设置为空。
const base = document.querySelector('base');
base.setAttribute('href', '');
将该代码放入App
组件(root wrap component)中以调用一次。
<强> 2。 componentDidMount
将其设置回来
componentDidMount() {
setTimeout(() => {
base.setAttribute('href', '/');
}, 1000);
}
使用超时等待反应完成渲染虚拟dom。
这是非常接近的,我认为(测试过)。因为您正在使用hash
路由器,所以来自索引html的链接将是安全的(不会被反应覆盖,而是通过base
标记保留)。它也适用于css链接<link rel="stylesheet" href="styles.css">
。
答案 1 :(得分:1)
如果您看到https://developer.mozilla.org/en-US/docs/Web/HTML/Element/base#Hint,则表示即使使用#target网址<base>
也是预期的行为。
在https://reacttraining.com/react-router/web/api/HashRouter上,它在basename:string部分中说明:格式正确的基本名称应该有一个前导斜杠,但没有尾部斜杠。
所以也许你应该在HashRouter
元素上定义一个不同的基本名称,或者从<base>
中删除尾部斜杠
答案 2 :(得分:1)
您对HashRouter
和<base>
标记的观察是正确的。我在此处提交了一个有关浏览器差异的问题:https://github.com/ReactTraining/history/issues/574以及相应的PR修复此处:https://github.com/ReactTraining/history/pull/577
与此同时,我不确定您需要的所有路由,但如果反应应用程序完全位于/some/static/page/
下,您可以将其用于:
<BrowserRouter basename="/some/static/page">
。
答案 3 :(得分:1)
我在HOC结束时只是应用this answer中描述的修复:
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>
...
答案 4 :(得分:1)
这是history
包的问题。它甚至已经解决,请查看this pr
作为临时修复,我建议您在package.json
"dependencies": {
...
"history": "git://github.com/amuzalevskiy/history.git",
...
}
一旦修复将合并到原始分支 - 将其恢复为固定的主要npm模块
关于回购:
我刚刚对microbouji solution做了npm run build
并提交了结果,因为如果不运行publish
脚本就无法使用原始存储库