如何在 React Router v4 中推送到历史记录?

IT技术 reactjs react-router react-router-v4
2021-04-20 23:25:43

在当前版本的 React Router (v3) 中,我可以接受服务器响应并用于browserHistory.push转到相应的响应页面。但是,这在 v4 中不可用,我不确定处理此问题的适当方法是什么。

在这个例子中,使用 Redux,components/app-product-form.jsthis.props.addProduct(props)在用户提交表单时调用当服务器返回成功时,用户被带到购物车页面。

// actions/index.js
export function addProduct(props) {
  return dispatch =>
    axios.post(`${ROOT_URL}/cart`, props, config)
      .then(response => {
        dispatch({ type: types.AUTH_USER });
        localStorage.setItem('token', response.data.token);
        browserHistory.push('/cart'); // no longer in React Router V4
      });
}

如何从 React Router v4 的功能重定向到购物车页面?

6个回答

您可以在history组件之外使用这些方法。按以下方法试试。

首先,创建一个history使用历史包对象

// src/history.js

import { createBrowserHistory } from 'history';

export default createBrowserHistory();

然后将其包裹起来<Router>请注意,您应该使用import { Router }代替import { BrowserRouter as Router }):

// src/index.jsx

// ...
import { Router, Route, Link } from 'react-router-dom';
import history from './history';

ReactDOM.render(
  <Provider store={store}>
    <Router history={history}>
      <div>
        <ul>
          <li><Link to="/">Home</Link></li>
          <li><Link to="/login">Login</Link></li>
        </ul>
        <Route exact path="/" component={HomePage} />
        <Route path="/login" component={LoginPage} />
      </div>
    </Router>
  </Provider>,
  document.getElementById('root'),
);

从任何地方更改您的当前位置,例如:

// src/actions/userActionCreators.js

// ...
import history from '../history';

export function login(credentials) {
  return function (dispatch) {
    return loginRemotely(credentials)
      .then((response) => {
        // ...
        history.push('/');
      });
  };
}

UPD:您还可以在React Router FAQ 中看到一个稍微不同的例子

我试图完全按照@OlegBelostotsky 所说的去做,但是之后history.push('some path'),URL 更改但页面没有更改。我必须window.location.reload()在我的代码的某些部分加上它才能让它工作。但是,在一种情况下,我必须保留 redux 状态树,而重新加载会破坏它。还有其他解决方案吗?
2021-05-27 23:25:43
@idunno 尝试使用withRouter高阶组件。
2021-05-27 23:25:43
确保您使用的是文档中指示的正确版本的历史记录在将 history v5 与 react router v5 一起使用时,我遇到了与 @sdabrutas 类似的问题(将 url 推送到历史记录但页面不会更改)。将历史降级到 v4 完全解决了这个问题。
2021-05-29 23:25:43
对不起,我的反对票:)。虽然这也应该有效,但正确的处理方法是 Chris 的回答:stackoverflow.com/a/42716055/491075
2021-06-17 23:25:43
这给我一个错误说明:createBrowserHistory 不是函数。我能做什么?
2021-06-18 23:25:43

React Router v4 与 v3(及更早版本)有着根本的不同,你不能browserHistory.push()以前那样做

如果您想了解更多信息,此讨论似乎相关:

  • 创建一个新的browserHistory将不起作用,因为<BrowserRouter>创建了它自己的历史实例,并监听了它的变化。因此,不同的实例将更改 url 但不会更新<BrowserRouter>.
  • browserHistory 在 v4 中没有被 react-router 暴露,只在 v2 中暴露。

相反,您有几个选项可以做到这一点:

  • 使用withRouter高阶组件

    相反,您应该使用withRouter高阶组件,并将其包装到将推送到历史记录的组件中。例如:

    import React from "react";
    import { withRouter } from "react-router-dom";
    
    class MyComponent extends React.Component {
      ...
      myFunction() {
        this.props.history.push("/some/Path");
      }
      ...
    }
    export default withRouter(MyComponent);
    

    查看官方文档了解更多信息:

    你可以访问history对象的属性和最近<Route>match经withRouter高阶组件。withRouter会在每次航线用相同的props改变时重新渲染它的组件作为<Route>渲染props:{ match, location, history }


  • 使用contextAPI

    使用上下文可能是最简单的解决方案之一,但作为实验性 API,它不稳定且不受支持。仅当其他一切都失败时才使用它。下面是一个例子:

    import React from "react";
    import PropTypes from "prop-types";
    
    class MyComponent extends React.Component {
      static contextTypes = {
        router: PropTypes.object
      }
      constructor(props, context) {
         super(props, context);
      }
      ...
      myFunction() {
        this.context.router.history.push("/some/Path");
      }
      ...
    }
    

    查看有关上下文官方文档

    如果您希望您的应用程序稳定,请不要使用上下文。它是一个实验性的 API,它可能会在 React 的未来版本中被破坏。

    如果您不顾这些警告坚持使用上下文,请尝试将您对上下文的使用隔离到一个小区域,并尽可能避免直接使用上下文 API,以便在 API 更改时更容易升级。

从 React 16.3 开始,上下文 API 不再是实验性的。React 的博客文章React v16.3.0:新的生命周期和上下文 API以获取有关该版本的更多信息。
2021-05-23 23:25:43
这并没有回答被问到的问题,即如何访问组件的 history.push OUTSIDE。使用 withRouter 或上下文不是组件外部的选项。
2021-05-28 23:25:43
我已经研究了这个主题几天了,但一直无法让它发挥作用。即使使用上面的示例,我也一直在上下文中未定义路由器。我目前正在使用 react v15.5.10、react-router-dom v4.1.1、prop-types 15.5.10。围绕此的文档很少而且不是很清楚。
2021-06-01 23:25:43
是的,我确实尝试过。谢谢你的提问。:-) 那么你如何将上下文加入到这个动作函数中呢?到目前为止,它是未定义的。
2021-06-02 23:25:43
@Stu 这应该有效 this.context.router.history.push('/path');
2021-06-16 23:25:43

现在使用 react-router v5,您可以像这样使用 useHistory 钩子:

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

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

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

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

阅读更多信息:https : //reacttraining.com/react-router/web/api/Hooks/usehistory

很好,但不能在 redux 动作类中使用钩子,因为它们不是 React 组件/函数
2021-05-27 23:25:43
@steff_bdh 您需要在 package.json 文件中将其更新为“react-router-dom”:“^5.0.1”并运行“npm install”
2021-05-30 23:25:43
引用 React 的话:“Hooks 只能在函数组件的主体内部调用。”
2021-06-01 23:25:43
您将如何在使用(异步)登录时使用它进行重定向。这是问题 => stackoverflow.com/questions/62154408/...
2021-06-05 23:25:43
有什么具体的方法需要设置吗,我正在调用以下方法,let history = useHistory();但出现Object is not callable错误,当我尝试查看 useHistory 是什么时,console.log(useHistory)它显示为未定义。使用"react-router-dom": "^5.0.1"
2021-06-18 23:25:43

React Router 4 中最简单的方法是使用

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

但是要使用这种方法,您现有的组件应该可以访问history对象。我们可以通过

  1. 如果您的组件Route直接链接到,那么您的组件已经可以访问history对象。

    例如:

    <Route path="/profile" component={ViewProfile}/>
    

    这里ViewProfile可以访问history.

  2. 如果不Route直接连接

    例如:

    <Route path="/users" render={() => <ViewUsers/>}
    

    然后我们必须使用withRouter,一个更高阶的函数来扭曲现有的组件。

    内部 ViewUsers组件

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

    • export default withRouter(ViewUsers);

    就是这样,您的ViewUsers组件可以访问history对象。

更新

2- 在这种情况下,将所有路由传递props给您的组件,然后this.props.history即使没有访问我们也可以从组件访问HOC

例如:

<Route path="/users" render={props => <ViewUsers {...props} />}
请注意,当您使用 时history.push,第二个参数是状态(请参阅reactrouter.com/web/api/history)。就我而言,我history.push('/same/route/I/am/currently/on', this.state)在更新状态的操作之后立即执行了操作。这会导致新状态被添加到历史堆栈中。然后在compoenntDidMount()我检查是否this.props.location.state已定义,如果已定义,则this.setState(this.props.location.state)在返回组件时调用以恢复状态。
2021-06-02 23:25:43
优秀的!您的第二种方法也对我有用,因为我的组件(需要访问this.props.history)来自 HOC,这意味着它没有直接链接到Route,正如您所解释的。
2021-06-04 23:25:43
这并没有回答原始问题如何在组件外使用历史记录
2021-06-11 23:25:43

我是这样做的:

import React, {Component} from 'react';

export default class Link extends Component {
    constructor(props) {
        super(props);
        this.onLogout = this.onLogout.bind(this);
    }
    onLogout() {
        this.props.history.push('/');
    }
    render() {
        return (
            <div>
                <h1>Your Links</h1>
                <button onClick={this.onLogout}>Logout</button>
            </div>
        );
    }
}

使用this.props.history.push('/cart');重定向到购物车页面将被保存在历史记录对象。

享受吧,迈克尔。

是的,它看起来像在您可以推送的组件中一样好。影响在组件外导航的唯一方法是使用重定向。
2021-06-02 23:25:43
这并没有回答被问到的问题,即如何访问组件的 history.push OUTSIDE。在组件外部时,不能使用 this.props.history 。
2021-06-14 23:25:43