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

IT技术 reactjs react-router
2021-03-31 23:18:21

随着react-router我可以使用Link元素来创建这些原生处理react-router链接。

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

我想做一个导航。不是来自链接,而是来自下拉选择(例如)。我怎样才能在代码中做到这一点?什么是this.context

我看到了Navigationmixin,但是我可以不用它mixins吗?

6个回答

带有钩子的 React Router v5.1.0

useHistory如果您使用 React > 16.8.0 和功能组件,则 React Router >5.1.0 中有一个新钩子。

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

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

  function handleClick() {
    history.push("/home");
  }

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

react-router v4

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

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

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

一个history实例有两种导航方法:pushreplace如果您将history视为访问过的位置push数组,replace则会向该数组添加一个新位置,并将用新位置替换该数组中的当前位置。通常,您会希望push在导航时使用该方法。

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

1.使用withRouter高阶组件

withRouter高次成分将注入的history对象作为所述部件的支柱。这允许您访问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>组件传递与 相同的propswithRouter,因此您将能够history通过historyprops访问这些方法

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

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

3. 使用上下文*

但你可能不应该

最后一个选项是只有在您觉得使用 React 的上下文模型很舒服时才应该使用的选项(React 的 Context API 从 v16 开始是稳定的)。

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 是最容易实现的选择,因此对于大多数用例,它们是您最好的选择。

我尝试以这种方式使用方法 1 withRouter(( { history } ) => { console.log("hhhhhhhh"); history.push('/bets') }); 但它从未与路由器 4 一起使用
2021-05-25 23:18:21
你怎么能在history.push('/new-location')不将该行为附加到 Button 或其他 DOM 元素的情况下运行呢?
2021-05-26 23:18:21
context 从 react 16 开始不再是实验性的了。
2021-05-31 23:18:21
更新:对于那些使用 eact-router-dom v6 的人应该使用 useNavigate() 而不是 useHistory()。有关更多详细信息,请参阅以下答案。stackoverflow.com/a/66971821/12572265
2021-05-31 23:18:21
什么!?我可以只使用withRouter而不是传递history我的所有组件?Gahh 我需要花更多的时间阅读文档...
2021-06-06 23:18:21

React-Router v6+答案

您可以使用新的useNavigate钩子。useNavigatehook 返回一个可用于编程导航的函数。react-router文档中的示例

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

function SignupForm() {
  let navigate = useNavigate();

  async function handleSubmit(event) {
    event.preventDefault();
    await submitForm(event.target);
    navigate("../success", { replace: true });
  }

  return <form onSubmit={handleSubmit}>{/* ... */}</form>;
}

React-Router 5.1.0+答案(使用钩子和 React > 16.8)

您可以使用useHistory功能组件上钩子并以编程方式导航:

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

function HomeButton() {
  let history = useHistory();
  // use history.push('/some/path') here
};

React-Router 4.0.0+答案

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

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

注意:如果您的组件不是由 呈现的,则 this.props.history 不存在<Route>您应该使用<Route path="..." component={YourComponent}/>在 YourComponent 中有 this.props.history

React-Router 3.0.0+答案

在 3.0 及更高版本中,使用路由器作为组件的props。

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

React-Router 2.4.0+答案

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

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 module,您可以使用它访问

import { browserHistory } from 'react-router'

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

browserHistory.push('/some/path')

进一步阅读: 历史导航


React-Router 1.xx答案

我不会讨论升级细节。您可以在升级指南中阅读相关内容

关于这里问题的主要变化是从导航混合到历史的变化。现在它使用浏览器 historyAPI 来更改路由,所以我们pushState()将从现在开始使用

下面是一个使用 Mixin 的例子:

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

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

如果您出于某种原因(可能是因为 ES6 类)不想使用 Mixin,那么您可以从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
};

React-Router-Redux

注:如果您使用的终极版,有一个名为另一个项目 ReactRouter,终极版,为您提供终极版绑定ReactRouter,有些使用了同样的方法 做出react,终极版

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>
太感谢了。文档很难搜索,以至于在 useNavigate 函数中使用 replace 既简单又有用,即使您知道要查找的内容,也很难找到。
2021-05-22 23:18:21

react-router v2

对于最新版本 ( v2.0.0-rc5),推荐的导航方法是直接推入历史单例。您可以在Navigating outside of Components 文档中看到这一点

相关摘录:

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

如果使用较新的 react-router API,则需要在组件内部使用historyfrom this.propswhen :

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

它还提供pushState但不推荐使用每个记录的警告。

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

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

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

不要忘记较新的 API 不使用import { browserHistory } from './react-router',而是使用import createBrowserHistory from 'history/lib/createBrowserHistory'. 稍后,您可以history从组件道具访问this.props.history('/some/path')
2021-06-02 23:18:21

这是react-router v2.0.0使用ES6执行此操作的方法react-router已经远离 mixin。

import React from 'react';

export default class MyComponent extends React.Component {
  navigateToPage = () => {
    this.context.router.push('/my-route')
  };

  render() {
    return (
      <button onClick={this.navigateToPage}>Go!</button>
    );
  }
}

MyComponent.contextTypes = {
  router: React.PropTypes.object.isRequired
}

React-Router 4.x 答案

最后,我喜欢有一个单一的历史对象,我什至可以携带外部组件。我喜欢有一个我按需导入的 history.js 文件,然后对其进行操作。

您只需要更改BrowserRouter为路由器,并指定历史props。这不会为您带来任何改变,只是您拥有自己的历史对象,可以根据需要进行操作。

您需要安装history使用的库react-router

示例用法,ES6表示法:

历史.js

import createBrowserHistory from 'history/createBrowserHistory'
export default createBrowserHistory()

基本组件.js

import React, { Component } from 'react';
import history from './history';

class BasicComponent extends Component {

    goToIndex(e){
        e.preventDefault();
        history.push('/');
    }

    render(){
        return <a href="#" onClick={this.goToIndex}>Previous</a>;
    }
}

如果您必须从实际从Route组件渲染的组件中导航,您还可以从 props 访问历史记录,如下所示:

基本组件.js

import React, { Component } from 'react';

class BasicComponent extends Component {

    navigate(e){
        e.preventDefault();
        this.props.history.push('/url');
    }

    render(){
        return <a href="#" onClick={this.navigate}>Previous</a>;
    }
}