React Router的HashRouter重定向到<base>标记网址

Est*_*ask 10 javascript base-tag base-url reactjs react-router

我有非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>
        );
    }
}
Run Code Online (Sandbox Code Playgroud)

可以禁用所有路由以进行测试,但这不会更改行为.

这是create-react-app显示问题的项目.复制它的步骤是:

  • 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>?它在这里使用完全是因为它不应该影响位置路径,只有哈希.

怎么解决这个问题?

hen*_*ngs 10

其实这从history。如果你看到他们的代码,他们使用 justcreateHashHistory和 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>
      );
    }
}
Run Code Online (Sandbox Code Playgroud)

它会显示您遇到的相同问题。然后,如果您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))
});
Run Code Online (Sandbox Code Playgroud)

那么你的问题会消失但绝对不会使用hash。所以问题不是来自 HashRouter而是来自history.

因为这来自history,让我们看看这个线程。读线程之后,我们可以采取的结论,这是功能history

所以,如果你设置了<base href="/">,因为你正在使用hash(#),当浏览器加载时(实际上是之后componentDidMount)它会hash在你的情况下附加(#) some/static/page=> some/static/page+ /=> /+ #/=> /#/。您可以在附加路由之前检查componentDidMount设置debugger以捕获。


解决方案

简单地说,只需删除元素<base href>或不使用HashRouter.

如果仍然需要但想避免特定的component,只需将其放在之前class

const base = document.querySelector("base");
base.setAttribute('href', '');
Run Code Online (Sandbox Code Playgroud)

更新

由于您想保留base标签以保持链接并使用hash路由器,因此我认为这是关闭的解决方案。

1. 将标签设置base为空。

const base = document.querySelector('base');
base.setAttribute('href', '');
Run Code Online (Sandbox Code Playgroud)

将该代码放在App组件(根包装组件)中以调用一次。

2.什么时候componentDidMount放回去

componentDidMount() {
  setTimeout(() => {
    base.setAttribute('href', '/');
  }, 1000);
}
Run Code Online (Sandbox Code Playgroud)

使用超时等待反应完成渲染虚拟 dom。

这非常接近,我想(测试一下)。因为您使用的是hash路由器,所以来自索引 html 的链接将是安全的(不是通过反应覆盖而是通过base标签保留)。它也适用于 css 链接<link rel="stylesheet" href="styles.css">