协慌网

登录 贡献 社区

使用 react 路由器以编程方式导航

使用react-router我可以使用Link元素创建由 react 路由器本地处理的链接。

我在内部看到它调用this.context.transitionTo(...)

我想进行导航,但不是从链接,例如下拉选择。我怎么能在代码中这样做?什么是this.context

我看到了Navigation mixin,但是我可以不使用 mixin 吗?

答案

反应路由器 v4

使用 React Router 的 v4,您可以采用三种方法在组件内进行编程路由。

  1. 使用withRouter高阶组件。
  2. 使用合成并渲染<Route>
  3. 使用context

React Router 主要是history库的包装器。 history通过浏览器和哈希历史history处理与浏览器window.history交互。它还提供了一个内存历史记录,对于没有全局历史记录的环境非常有用。这在移动应用程序开发( react-native )和 Node 的单元测试中特别有用。

history实例有两种导航方法: pushreplace 。如果您将history视为已访问位置的数组,则push将向阵列添加新位置,并且replace将使用新位置replace阵列中的当前位置。通常,您需要在导航时使用push方法。

在早期版本的 React Router 中,您必须创建自己的history实例,但在第 4 版中, <BrowserRouter><HashRouter><MemoryRouter>组件将为您创建浏览器,哈希和内存实例。 React Router 通过router对象下的上下文使与路由器关联的history实例的属性和方法可用。

1. 使用withRouter高阶组件

withRouter高阶组件将history对象注入为组件的 prop。这允许您访问pushreplace方法,而无需处理context

import { withRouter } from 'react-router-dom'
// this also works with react-router-native

const Button = withRouter(({ history }) => (
  <button
    type='button'
    onClick={() => { history.push('/new-location') }}
  >
    Click Me!
  </button>
))

2. 使用合成并渲染<Route>

<Route>组件不仅适用于匹配位置。您可以渲染无路径路径, 它始终与当前位置匹配<Route>组件传递与withRouter相同的道具,因此您将能够通过history道具访问history方法。

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

const Button = () => (
  <Route render={({ history}) => (
    <button
      type='button'
      onClick={() => { history.push('/new-location') }}
    >
      Click Me!
    </button>
  )} />
)

3. 使用上下文 *

但你可能不应该这样做

最后一个选项是您只有在使用 React 的上下文模型时才能使用的选项。虽然上下文是一个选项,但应该强调上下文是一个不稳定的 API,React 在其文档中有一节“不使用上下文” 。所以使用风险自负!

const Button = (props, context) => (
  <button
    type='button'
    onClick={() => {
      // context.history.push === history.push
      context.history.push('/new-location')
    }}
  >
    Click Me!
  </button>
)

// you need to specify the context type so that it
// is available within the component
Button.contextTypes = {
  history: React.PropTypes.shape({
    push: React.PropTypes.func.isRequired
  })
}

1 和 2 是最简单的选择,因此对于大多数用例来说,它们是您最好的选择。

React-Router 4.0.0+答案

在 4.0 及更高版本中,使用历史记录作为组件的支柱。

class Example extends React.Component {
   // use `this.props.history.push('/some/path')` here
};

React-Router 3.0.0+答案

在 3.0 及以上版本中,使用路由器作为组件的支柱。

class Example extends React.Component {
   // use `this.props.router.push('/some/path')` here
};

React-Router 2.4.0+答案

在 2.4 及更高版本中,使用更高阶的组件将路由器作为组件的支柱。

import { withRouter } from 'react-router';

class Example extends React.Component {
   // use `this.props.router.push('/some/path')` here
};

// Export the decorated class
var DecoratedExample = withRouter(Example);

// PropTypes
Example.propTypes = {
  router: React.PropTypes.shape({
    push: React.PropTypes.func.isRequired
  }).isRequired
};

React-Router 2.0.0+答案

此版本向后兼容 1.x,因此无需升级指南。只是通过这些例子应该足够好了。

也就是说,如果你想切换到新的模式,路由器内部就有一个 browserHistory 模块可以访问

import { browserHistory } from 'react-router'

现在您可以访问浏览器历史记录,因此您可以执行推送,替换等操作...

browserHistory.push('/some/path')

进一步阅读: 历史导航


React-Router 1.xx答案

我不打算升级细节。您可以在 “ 升级指南” 中阅读相关内容

这里问题的主要变化是从导航 mixin 到 History 的变化。现在它正在使用浏览器 historyAPI 来改变路由,所以从现在开始我们将使用pushState()

这是使用 Mixin 的例子:

var Example = React.createClass({
  mixins: [ History ],
  navigateToHelpPage () {
    this.history.pushState(null, `/help`);
  }
})

请注意,此History来自rackt / history项目。不是来自 React-Router 本身。

如果您由于某种原因不想使用 Mixin(可能是因为 ES6 类),那么您可以从this.props.history访问从路由器获得的历史记录。它只能由路由器呈现的组件访问。所以,如果你想在任何子组件中使用它,它需要通过props作为属性传递下来。

您可以在1.0.x 文档中阅读有关新版本的更多信息

这是一个专门关于在组件外部导航的帮助页面

它建议抓取引用history = createHistory()并在其上调用replaceState

React-Router 0.13.x答案

我遇到了同样的问题,只能通过 react-router 附带的 Navigation mixin 找到解决方案。

这就是我做到的

import React from 'react';
import {Navigation} from 'react-router';

let Authentication = React.createClass({
  mixins: [Navigation],

  handleClick(e) {
    e.preventDefault();

    this.transitionTo('/');
  },

  render(){
    return (<div onClick={this.handleClick}>Click me!</div>);
  }
});

我能够调用transitionTo()而无需访问.context

或者你可以尝试花哨的 ES6 class

import React from 'react';

export default class Authentication extends React.Component {
  constructor(props) {
    super(props);
    this.handleClick = this.handleClick.bind(this);
  }

  handleClick(e) {
    e.preventDefault();

    this.context.router.transitionTo('/');
  }

  render(){
    return (<div onClick={this.handleClick}>Click me!</div>);
  }
}

Authentication.contextTypes = {
  router: React.PropTypes.func.isRequired
};

反应 - 路由器 - 终极版

注意:如果您正在使用 Redux,还有另一个名为React-Router-Redux 的项目 ,它为 ReactRouter 提供了 redux 绑定,使用的方法与React-Redux 的方法相同

React-Router-Redux 有一些可用的方法,允许从内部动作创建者进行简单的导航。这些对于在 React Native 中具有现有体系结构的人来说特别有用,并且他们希望在 React Web 中使用相同的模式,并且具有最小的样板开销。

探索以下方法:

  • push(location)
  • replace(location)
  • go(number)
  • goBack()
  • goForward()

以下是使用Redux-Thunk的示例用法:

./actioncreators.js

import { goBack } from 'react-router-redux'

export const onBackPress = () => (dispatch) => dispatch(goBack())

./viewcomponent.js

<button
  disabled={submitting}
  className="cancel_button"
  onClick={(e) => {
    e.preventDefault()
    this.props.onBackPress()
  }}
>
  CANCEL
</button>

React-Router v2

对于最新版本( v2.0.0-rc5 ),推荐的导航方法是直接推送到历史单例。您可以在 “ 组件外部导航” 文档中看到该操作。

相关摘录:

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

如果使用较新的 react-router API,则需要在组件内部使用this.props中的history ,这样:

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

它还提供pushState但每个已记录的警告都会弃用。

如果使用react-router-redux ,它提供了一个push函数,你可以像这样调度:

import { push } from 'react-router-redux';
this.props.dispatch(push('/some/path'));

但是,这可能仅用于更改 URL,而不是实际导航到页面。