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

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

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


当前回答

如果你的目标是浏览器环境,你需要使用react-router-dom包,而不是react-router。他们遵循与React相同的方法,为了分离核心(React)和特定于平台的代码(React -dom, React -native),有细微的区别,你不需要安装两个单独的包,所以环境包包含了你需要的一切。你可以把它添加到你的项目中:

Yarn添加react-router-dom

or

我react-router-dom

您需要做的第一件事是提供一个<BrowserRouter>作为应用程序中最顶层的父组件。<BrowserRouter>使用HTML5历史API并为您管理它,因此您不必担心自己实例化它并将其传递给<BrowserRouter>组件作为道具(正如您在以前的版本中需要做的那样)。

在V4中,为了以编程方式导航,你需要访问历史对象,它可以通过React上下文获得,只要你在应用程序中有一个<BrowserRouter>提供者组件作为最顶层的父组件。该库通过上下文公开路由器对象,该对象本身包含历史作为属性。历史界面提供了一些导航方法,例如push、replace和goBack等。您可以在这里查看整个属性和方法列表。

Redux/Mobx用户注意事项 如果您在应用程序中使用redux或mobx作为状态管理库,那么您可能会遇到组件应该是位置感知的,但在触发URL更新后没有重新呈现的问题

这是因为react-router使用上下文模型将位置传递给组件。

connect和observer都创建了组件,它们的shouldComponentUpdate方法会对当前的道具和下一个道具进行简单的比较。这些组件只有在至少一个道具发生变化时才会重新渲染。这意味着,为了确保它们在位置更改时更新,它们将需要在位置更改时更改道具。

解决这个问题的两种方法是:

将连接的组件包装在一个无路径的<Route />。当前位置对象是<Route>传递给它呈现的组件的道具之一 使用withRouter高阶组件包装连接的组件,实际上具有相同的效果,并将位置作为道具注入

撇开这个不谈,有四种按推荐顺序进行编程导航的方法:

1.- Using a <Route> Component It promotes a declarative style. Prior to v4, <Route /> components were placed at the top of your component hierarchy, having to think of your routes structure beforehand. However, now you can have <Route> components anywhere in your tree, allowing you to have a finer control for conditionally rendering depending on the URL. Route injects match, location and history as props into your component. The navigation methods (such as push, replace, goBack...) are available as properties of the history object.

有三种方法来渲染一个Route,通过使用组件,渲染或子道具,但不要在同一个Route中使用多个。选择取决于用例,但基本上前两个选项只在路径与url位置匹配时才会呈现组件,而对于子组件,无论路径与位置是否匹配都将呈现(这对于基于url匹配调整UI很有用)。

如果你想定制你的组件渲染输出,你需要将你的组件包装在一个函数中,并使用渲染选项,以便传递给你的组件任何其他你想要的道具,除了匹配,位置和历史记录。举例说明:

import { BrowserRouter as Router } from 'react-router-dom'

const ButtonToNavigate = ({ title, history }) => (
  <button
    type="button"
    onClick={() => history.push('/my-new-location')}
  >
    {title}
  </button>
);

const SomeComponent = () => (
  <Route path="/" render={(props) => <ButtonToNavigate {...props} title="Navigate elsewhere" />} />
)    

const App = () => (
  <Router>
    <SomeComponent /> // Notice how in v4 we can have any other component interleaved
    <AnotherComponent />
  </Router>
);

2.-与throuter HoC一起使用

这个高阶组件将注入与Route相同的道具。但是,它有一个限制,每个文件只能有1个HoC。

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

const ButtonToNavigate = ({ history }) => (
  <button
    type="button"
    onClick={() => history.push('/my-new-location')}
  >
    Navigate
  </button>
);


ButtonToNavigate.propTypes = {
  history: React.PropTypes.shape({
    push: React.PropTypes.func.isRequired,
  }),
};

export default withRouter(ButtonToNavigate);

3.使用重定向组件渲染<Redirect>将导航到一个新的位置。但是请记住,默认情况下,当前位置将被新位置替换,如服务器端重定向(HTTP 3xx)。新的位置由to prop提供,它可以是一个字符串(要重定向到的URL)或一个location对象。如果您想将一个新条目推送到历史记录中,也可以传递一个推送道具,并将其设置为true

<Redirect to="/your-new-location" push />

4.有点不鼓励,因为上下文仍然是一个实验性的API,它很可能在React的未来版本中被破坏/改变

const ButtonToNavigate = (props, context) => (
  <button
    type="button"
    onClick={() => context.router.history.push('/my-new-location')}
  >
    Navigate to a new location
  </button>
);

ButtonToNavigate.contextTypes = {
  router: React.PropTypes.shape({
    history: React.PropTypes.object.isRequired,
  }),
};

不用说,还有其他的路由器组件是针对非浏览器生态系统的,比如<NativeRouter>,它在内存中复制了一个导航堆栈,目标是React Native平台,可以通过React - Router - Native包获得。

如需进一步参考,请参阅官方文档。还有一个由该库的共同作者之一制作的视频,该视频非常酷地介绍了react-router v4,突出了一些主要的变化。

其他回答

最简单的方法是:

this.props.history.push(“/new/url”)

注意:

如果历史道具不可用,你可以将它从父组件传递到你想调用该动作的组件。

我认为@rgommezz涵盖了大多数情况,除了一个我认为非常重要的情况。

// history is already a dependency or React Router, but if don't have it then try npm install save-dev history

import createHistory from "history/createBrowserHistory"

// in your function then call add the below 
const history = createHistory();
// Use push, replace, and go to navigate around.
history.push("/home");

这允许我写一个简单的服务与动作/调用,我可以调用从任何组件做导航,而不需要在我的组件上做很多HoC…

目前还不清楚为什么以前没有人提供这种解决方案。我希望它能有所帮助,如果你看到任何问题,请告诉我。

第一步:只需要在上面导入一个东西:

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

第二步:在Route中,传递历史记录:

<Route
  exact
  path='/posts/add'
  render={({history}) => (
    <PostAdd history={history} />
  )}
/>

第三步:历史被接受为下一个组件的道具的一部分,所以你可以简单地:

this.props.history.push('/');

这很简单,也很有力。

如果你的目标是浏览器环境,你需要使用react-router-dom包,而不是react-router。他们遵循与React相同的方法,为了分离核心(React)和特定于平台的代码(React -dom, React -native),有细微的区别,你不需要安装两个单独的包,所以环境包包含了你需要的一切。你可以把它添加到你的项目中:

Yarn添加react-router-dom

or

我react-router-dom

您需要做的第一件事是提供一个<BrowserRouter>作为应用程序中最顶层的父组件。<BrowserRouter>使用HTML5历史API并为您管理它,因此您不必担心自己实例化它并将其传递给<BrowserRouter>组件作为道具(正如您在以前的版本中需要做的那样)。

在V4中,为了以编程方式导航,你需要访问历史对象,它可以通过React上下文获得,只要你在应用程序中有一个<BrowserRouter>提供者组件作为最顶层的父组件。该库通过上下文公开路由器对象,该对象本身包含历史作为属性。历史界面提供了一些导航方法,例如push、replace和goBack等。您可以在这里查看整个属性和方法列表。

Redux/Mobx用户注意事项 如果您在应用程序中使用redux或mobx作为状态管理库,那么您可能会遇到组件应该是位置感知的,但在触发URL更新后没有重新呈现的问题

这是因为react-router使用上下文模型将位置传递给组件。

connect和observer都创建了组件,它们的shouldComponentUpdate方法会对当前的道具和下一个道具进行简单的比较。这些组件只有在至少一个道具发生变化时才会重新渲染。这意味着,为了确保它们在位置更改时更新,它们将需要在位置更改时更改道具。

解决这个问题的两种方法是:

将连接的组件包装在一个无路径的<Route />。当前位置对象是<Route>传递给它呈现的组件的道具之一 使用withRouter高阶组件包装连接的组件,实际上具有相同的效果,并将位置作为道具注入

撇开这个不谈,有四种按推荐顺序进行编程导航的方法:

1.- Using a <Route> Component It promotes a declarative style. Prior to v4, <Route /> components were placed at the top of your component hierarchy, having to think of your routes structure beforehand. However, now you can have <Route> components anywhere in your tree, allowing you to have a finer control for conditionally rendering depending on the URL. Route injects match, location and history as props into your component. The navigation methods (such as push, replace, goBack...) are available as properties of the history object.

有三种方法来渲染一个Route,通过使用组件,渲染或子道具,但不要在同一个Route中使用多个。选择取决于用例,但基本上前两个选项只在路径与url位置匹配时才会呈现组件,而对于子组件,无论路径与位置是否匹配都将呈现(这对于基于url匹配调整UI很有用)。

如果你想定制你的组件渲染输出,你需要将你的组件包装在一个函数中,并使用渲染选项,以便传递给你的组件任何其他你想要的道具,除了匹配,位置和历史记录。举例说明:

import { BrowserRouter as Router } from 'react-router-dom'

const ButtonToNavigate = ({ title, history }) => (
  <button
    type="button"
    onClick={() => history.push('/my-new-location')}
  >
    {title}
  </button>
);

const SomeComponent = () => (
  <Route path="/" render={(props) => <ButtonToNavigate {...props} title="Navigate elsewhere" />} />
)    

const App = () => (
  <Router>
    <SomeComponent /> // Notice how in v4 we can have any other component interleaved
    <AnotherComponent />
  </Router>
);

2.-与throuter HoC一起使用

这个高阶组件将注入与Route相同的道具。但是,它有一个限制,每个文件只能有1个HoC。

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

const ButtonToNavigate = ({ history }) => (
  <button
    type="button"
    onClick={() => history.push('/my-new-location')}
  >
    Navigate
  </button>
);


ButtonToNavigate.propTypes = {
  history: React.PropTypes.shape({
    push: React.PropTypes.func.isRequired,
  }),
};

export default withRouter(ButtonToNavigate);

3.使用重定向组件渲染<Redirect>将导航到一个新的位置。但是请记住,默认情况下,当前位置将被新位置替换,如服务器端重定向(HTTP 3xx)。新的位置由to prop提供,它可以是一个字符串(要重定向到的URL)或一个location对象。如果您想将一个新条目推送到历史记录中,也可以传递一个推送道具,并将其设置为true

<Redirect to="/your-new-location" push />

4.有点不鼓励,因为上下文仍然是一个实验性的API,它很可能在React的未来版本中被破坏/改变

const ButtonToNavigate = (props, context) => (
  <button
    type="button"
    onClick={() => context.router.history.push('/my-new-location')}
  >
    Navigate to a new location
  </button>
);

ButtonToNavigate.contextTypes = {
  router: React.PropTypes.shape({
    history: React.PropTypes.object.isRequired,
  }),
};

不用说,还有其他的路由器组件是针对非浏览器生态系统的,比如<NativeRouter>,它在内存中复制了一个导航堆栈,目标是React Native平台,可以通过React - Router - Native包获得。

如需进一步参考,请参阅官方文档。还有一个由该库的共同作者之一制作的视频,该视频非常酷地介绍了react-router v4,突出了一些主要的变化。

我为此纠结了一段时间——如此简单,却又如此复杂,因为ReactJS只是一种完全不同的web应用程序编写方式,这对我们这些老年人来说非常陌生!

我创建了一个单独的组件来抽象混乱:

// LinkButton.js

import React from "react";
import PropTypes from "prop-types";
import {Route} from 'react-router-dom';

export default class LinkButton extends React.Component {

    render() {
        return (
            <Route render={({history}) => (
                <button {...this.props}
                       onClick={() => {
                           history.push(this.props.to)
                       }}>
                    {this.props.children}
                </button>
            )}/>
        );
    }
}

LinkButton.propTypes = {
    to: PropTypes.string.isRequired
};

然后将它添加到render()方法中:

<LinkButton className="btn btn-primary" to="/location">
    Button Text
</LinkButton>