我刚刚把react-router从v3替换为v4。 但我不确定如何以编程方式在组件的成员函数中导航。 即在handleClick()函数中,我想在处理一些数据后导航到/path/some/where。 我以前是这样做的:

import { browserHistory } from 'react-router'
browserHistory.push('/path/some/where')

但是我在v4中找不到这样的界面。 如何使用v4导航?


当前回答

如果使用函数组件,请使用useHistory钩子

你可以使用useHistory钩子获取历史实例。

import { useHistory } from "react-router-dom";

const MyComponent = () => {
  const history = useHistory();
  
  return (
    <button onClick={() => history.push("/about")}>
      Click me
    </button>
  );
}

useHistory钩子使您可以访问用于导航的历史实例。

在页面组件中使用history属性

React Router向页面组件注入一些属性,包括历史记录。

class HomePage extends React.Component {
  render() {
    const { history } = this.props;

    return (
      <div>
        <button onClick={() => history.push("/projects")}>
          Projects
        </button>
      </div>
    );
  }
}

用throuter包装子组件以注入路由器属性

withRouter包装器将路由器属性注入组件。例如,您可以使用此包装器注入路由器注销按钮组件放置在用户菜单。

import { withRouter } from "react-router";

const LogoutButton = withRouter(({ history }) => {
  return (
    <button onClick={() => history.push("/login")}>
      Logout
    </button>
  );
});

export default LogoutButton;

其他回答

我在迁移到React-Router v4时遇到了类似的问题,因此我将在下面解释我的解决方案。

请不要认为这个答案是解决问题的正确方法,我想随着React Router v4变得更加成熟并离开beta版,很有可能会出现更好的答案(它甚至可能已经存在,只是我没有发现它)。

就上下文而言,我遇到了这个问题,因为我偶尔使用Redux-Saga以编程方式更改历史对象(例如当用户成功验证时)。

在React Router文档中,看一下<Router>组件,你可以看到你有能力通过道具传递自己的历史对象。这是解决方案的本质——我们从全局模块向React-Router提供历史对象。

步骤:

Install the history npm module - yarn add history or npm install history --save create a file called history.js in your App.js level folder (this was my preference) // src/history.js import createHistory from 'history/createBrowserHistory'; export default createHistory();` Add this history object to your Router component like so // src/App.js import history from '../your/path/to/history.js;' <Router history={history}> // Route tags here </Router> Adjust the URL just like before by importing your global history object: import history from '../your/path/to/history.js;' history.push('new/path/here/');

现在所有内容都应该保持同步,您还可以通过编程方式设置历史对象,而不是通过组件/容器。

我的答案和Alex的相似。我不知道为什么React-Router把这个做得如此复杂。为什么我必须用一个HoC来包装我的组件,只是为了访问本质上是全局的?

不管怎样,如果你看一下他们是如何实现<BrowserRouter>的,它只是一个历史记录的小包装。

我们可以把这段历史提取出来,这样我们就可以从任何地方导入。然而,诀窍在于,如果您正在进行服务器端呈现,并试图导入历史模块,那么它将无法工作,因为它使用的是纯浏览器api。但这没关系,因为我们通常只在响应单击或其他客户端事件时重定向。因此,假装一下是可以的:

// history.js
if(__SERVER__) {
    module.exports = {};
} else {
    module.exports = require('history').createBrowserHistory();
}

在webpack的帮助下,我们可以定义一些变量,这样我们就知道我们所处的环境:

plugins: [
    new DefinePlugin({
        '__SERVER__': 'false',
        '__BROWSER__': 'true', // you really only need one of these, but I like to have both
    }),

现在你可以

import history from './history';

从任何地方。它只会在服务器上返回一个空模块。

如果你不想使用这些神奇的变量,你只需要在需要它的全局对象中(在你的事件处理程序中)。导入不能工作,因为它只在顶层工作。

对于那些在使用React router或React router Dom完全初始化路由器之前需要重定向的人,你可以通过简单地访问历史对象并在app.js的结构中将一个新状态推到它上来提供重定向。考虑以下几点:

function getSubdomain(hostname) {
    let regexParse = new RegExp('[a-z\-0-9]{2,63}\.[a-z\.]{2,5}$');
    let urlParts = regexParse.exec(hostname);
    return hostname.replace(urlParts[0], '').slice(0, -1);
}

class App extends Component {

    constructor(props) {
        super(props);


        this.state = {
            hostState: true
        };

        if (getSubdomain(window.location.hostname).length > 0) {
            this.state.hostState = false;
            window.history.pushState('', '', './login');
        } else {
            console.log(getSubdomain(window.location.hostname));
        }

    }


    render() {
        return (

            <BrowserRouter>
                {this.state.hostState ? (
                    <div>
                        <Route path="/login" component={LoginContainer}/>
                        <Route path="/" component={PublicContainer}/>
                    </div>
                ) : (
                    <div>
                        <Route path="/login" component={LoginContainer}/>
                    </div>
                )

                }
            </BrowserRouter>)
    }


}

在这里,我们想要改变依赖于子域的输出路由,通过在组件呈现之前与历史对象交互,我们可以有效地重定向,同时仍然保留我们的路由。

window.history.pushState('', '', './login');

如此:

import { withRouter } from 'react-router-dom';

const SomeComponent = withRouter(({ history }) => (
    <div onClick={() => history.push('/path/some/where')}>
        some clickable element
    </div>); 
);

export default SomeComponent;

你可以通过这种方式有条件地导航

import { useHistory } from "react-router-dom";

function HomeButton() {
  const history = useHistory();

  function handleClick() {
    history.push("/path/some/where");
  }

  return (
    <button type="button" onClick={handleClick}>
      Go home
    </button>
  );
}