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

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

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


当前回答

由于没有其他方法来处理这个可怕的设计,所以我编写了一个使用withRouter HOC方法的通用组件。下面的例子是包装一个按钮元素,但你可以更改为任何你需要的可点击元素:

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

const NavButton = (props) => (
  <Button onClick={() => props.history.push(props.to)}>
    {props.children}
  </Button>
);

NavButton.propTypes = {
  history: PropTypes.shape({
    push: PropTypes.func.isRequired
  }),
  to: PropTypes.string.isRequired
};

export default withRouter(NavButton);

用法:

<NavButton to="/somewhere">Click me</NavButton>

其他回答

我在迁移到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/');

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

this.props.history.push("/url")

如果您在组件中没有找到this.props.history可用, 那就试试这个

import {withRouter} from 'react-router-dom'
export default withRouter(MyComponent)  

TL; diana:

if (navigate) {
  return <Redirect to="/" push={true} />
}

简单和声明性的答案是,您需要结合setState()使用<Redirect to={URL} push={boolean} />

Push:布尔值——当为true时,重定向将把一个新条目推到历史记录中,而不是替换当前的条目。


import { Redirect } from 'react-router'

class FooBar extends React.Component {
  state = {
    navigate: false
  }

  render() {
    const { navigate } = this.state

    // here is the important part
    if (navigate) {
      return <Redirect to="/" push={true} />
    }
   // ^^^^^^^^^^^^^^^^^^^^^^^

    return (
      <div>
        <button onClick={() => this.setState({ navigate: true })}>
          Home
        </button>
      </div>
    )
  }
}

完整的例子。 点击这里阅读更多。

本例使用ES7+属性初始化器初始化状态。如果你感兴趣的话,也看看这里。

如果你的目标是浏览器环境,你需要使用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,突出了一些主要的变化。

你也可以简单地使用props来访问历史对象: