首页 文章

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

提问于
浏览
191

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

在此示例中,使用Redux,components / app-product-form.js在用户提交表单时调用 this.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的功能重定向到Cart页面?

16 回答

  • 0
    /*Step 1*/
    myFunction(){  this.props.history.push("/home"); }
    /**/
     <button onClick={()=>this.myFunction()} className={'btn btn-primary'}>Go 
     Home</button>
    
  • 1

    您可以在组件外部使用 history 方法 . 请尝试以下方式 .

    首先,创建一个 history 对象the history package

    // src/history.js
    
    import { createBrowserHistory } from 'history';
    
    export default createBrowserHistory();
    

    然后将其包装在 <Router>please note ,你应该使用 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中看到略有不同的示例 .

  • 2

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

    如果您想要更多信息,This discussion似乎相关:

    创建新的browserHistory将无法工作,因为<BrowserRouter>会创建自己的历史记录实例,并侦听其中的更改 . 因此,不同的实例将更改URL但不更新<BrowserRouter> . 仅在v2中,v4中的react-path不会公开browserHistory .


    相反,你有几个选项来做到这一点:

    使用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);
    

    查看official documentation了解更多信息:

    您可以通过withRouter高阶组件访问历史对象的属性和最接近的<Route>的匹配 . 每当路径改变时,withRouter将重新渲染其组件,其中包含与<Route>渲染道具相同的道具:{match,location,history} .


    使用上下文API

    使用上下文可能是最简单的解决方案之一,但作为实验性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");
      }
      ...
    }
    

    看看上下文中的official documentation

    如果您希望应用程序稳定,请不要使用上下文 . 它是一个实验性API,很可能会在未来的React版本中破解 . 如果您坚持使用上下文尽管存在这些警告,请尝试将上下文的使用隔离到一个小区域,并尽可能避免直接使用上下文API,以便在API更改时更容易升级 .

  • 4

    这就是我做的方式:

    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'); 重定向到购物车页面,它将保存在历史记录对象中 .

    享受,迈克尔 .

  • 19

    根据React Router v4 documentation - Redux Deep Integration session

    需要深度整合:

    “能够通过调度动作导航”

    但是,他们建议采用这种方法作为“深度整合”的替代方案:

    “除了调度导航操作之外,您还可以将提供的历史记录对象传递给您的操作并在其中导航 . ”

    因此,您可以使用withRouter高阶组件包装组件:

    export default withRouter(connect(null, { actionCreatorName })(ReactComponent));

    这会将历史API传递给道具 . 所以你可以调用动作创建者将历史作为参数传递 . 例如,在ReactComponent中:

    onClick={() => {
      this.props.actionCreatorName(
        this.props.history,
        otherParams
      );
    }}
    

    然后,在你的actions / index.js里面:

    export function actionCreatorName(history, param) {
      return dispatch => {
        dispatch({
          type: SOME_ACTION,
          payload: param.data
        });
        history.push("/path");
      };
    }
    
  • 237

    React路由器V4现在允许使用历史支柱如下:

    this.props.history.push("/dummy",value)
    

    然后,只要位置prop可用,就可以访问该值,因为 state:{value} 不是组件状态 .

  • 0

    你可以像这样使用它来登录和manny不同的东西

    class Login extends Component {
      constructor(props){
        super(props);
        this.login=this.login.bind(this)
      }
    
    
      login(){
    this.props.history.push('/dashboard');
      }
    
    
    render() {
    
        return (
    
       <div>
        <button onClick={this.login}>login</login>
        </div>
    
    )
    
  • 0

    讨厌的问题,花了我很多时间,但最终,我这样解决了:

    使用 withRouter 包装容器并将历史记录传递给 mapDispatchToProps 函数中的操作 . 在操作中使用history.push('/url')进行导航 .

    行动:

    export function saveData(history, data) {
      fetch.post('/save', data)
         .then((response) => {
           ...
           history.push('/url');
         })
    };
    

    容器:

    import { withRouter } from 'react-router-dom';
    ...
    const mapDispatchToProps = (dispatch, ownProps) => {
      return {
        save: (data) => dispatch(saveData(ownProps.history, data))}
    };
    export default withRouter(connect(mapStateToProps, mapDispatchToProps)(Container));
    

    这适用于 React Router v4.x .

  • 4

    this.context.history.push 无效 .

    我成功地推动了这样的工作:

    static contextTypes = {
        router: PropTypes.object
    }
    
    handleSubmit(e) {
        e.preventDefault();
    
        if (this.props.auth.success) {
            this.context.router.history.push("/some/Path")
        }
    
    }
    
  • 1

    在这种情况下,你将道具传递给你的thunk . 所以你可以简单地打电话

    props.history.push('/cart')
    

    如果不是这种情况,您仍然可以从组件中传递历史记录

    export function addProduct(data, history) {
      return dispatch => {
        axios.post('/url', data).then((response) => {
          dispatch({ type: types.AUTH_USER })
          history.push('/cart')
        })
      }
    }
    
  • 2

    我提供了一个解决方案,以防其他人有 Value .

    我有一个 history.js 文件,其中包含以下内容:

    import createHistory from 'history/createBrowserHistory'
    const history = createHistory()
    history.pushLater = (...args) => setImmediate(() => history.push(...args))
    export default history
    

    接下来,在我定义路由器的Root上,我使用以下内容:

    import history from '../history'
    import { Provider } from 'react-redux'
    import { Router, Route, Switch } from 'react-router-dom'
    
    export default class Root extends React.Component {
      render() {
        return (
         <Provider store={store}>
          <Router history={history}>
           <Switch>
            ...
           </Switch>
          </Router>
         </Provider>
        )
       }
      }
    

    最后,在我的 actions.js 我导入历史记录并使用pushLater

    import history from './history'
    export const login = createAction(
    ...
    history.pushLater({ pathname: PATH_REDIRECT_LOGIN })
    ...)
    

    这样,我可以在API调用后推送到新的操作 .

    希望能帮助到你!

  • 13

    使用回调 . 它对我有用!

    export function addProduct(props, callback) {
      return dispatch =>
        axios.post(`${ROOT_URL}/cart`, props, config)
        .then(response => {
        dispatch({ type: types.AUTH_USER });
        localStorage.setItem('token', response.data.token);
        callback();
      });
    }
    

    在组件中,您只需添加回调

    this.props.addProduct(props, () => this.props.history.push('/cart'))
    
  • 14

    如果您使用的是Redux,那么我建议使用npm package react-router-redux . 它允许您调度Redux商店导航操作 .

    您必须按Readme file中所述创建商店 .

    The easiest use case:

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

    Second use case with Container/Component:

    容器:

    import { connect } from 'react-redux';
    import { push } from 'react-router-redux';
    
    import Form from '../components/Form';
    
    const mapDispatchToProps = dispatch => ({
      changeUrl: url => dispatch(push(url)),
    });
    
    export default connect(null, mapDispatchToProps)(Form);
    

    零件:

    import React, { Component } from 'react';
    import PropTypes from 'prop-types';
    
    export default class Form extends Component {
      handleClick = () => {
        this.props.changeUrl('/secondPage');
      };
    
      render() {
        return (
          <div>
            <button onClick={this.handleClick}/>
          </div>Readme file
        );
      }
    }
    
  • 3

    我能够通过使用 bind() 来实现这一目标 . 我想单击 index.jsx 中的按钮,将一些数据发布到服务器,评估响应,然后重定向到 success.jsx . 这就是我的工作方式那......

    index.jsx

    import React, { Component } from "react"
    import { postData } from "../../scripts/request"
    
    class Main extends Component {
        constructor(props) {
            super(props)
            this.handleClick = this.handleClick.bind(this)
            this.postData = postData.bind(this)
        }
    
        handleClick() {
            const data = {
                "first_name": "Test",
                "last_name": "Guy",
                "email": "test@test.com"
            }
    
            this.postData("person", data)
        }
    
        render() {
            return (
                <div className="Main">
                    <button onClick={this.handleClick}>Test Post</button>
                </div>
            )
        }
    }
    
    export default Main
    

    request.js

    import { post } from "./fetch"
    
    export const postData = function(url, data) {
        // post is a fetch() in another script...
        post(url, data)
            .then((result) => {
                if (result.status === "ok") {
                    this.props.history.push("/success")
                }
            })
    }
    

    success.jsx

    import React from "react"
    
    const Success = () => {
        return (
            <div className="Success">
                Hey cool, got it.
            </div>
        )
    }
    
    export default Success
    

    所以通过将 this 绑定到 index.jsx 中的 postData ,我能够在 request.js 中访问 this.props.history ...然后我可以在不同的组件中重用此函数,只需要确保我记得在 constructor() 中包含 this.postData = postData.bind(this) .

  • 6

    这里's my hack (this is my root-level file, with a little redux mixed in there - though I'我没有使用 react-router-redux ):

    const store = configureStore()
    const customHistory = createBrowserHistory({
      basename: config.urlBasename || ''
    })
    
    ReactDOM.render(
      <Provider store={store}>
        <Router history={customHistory}>
          <Route component={({history}) => {
            window.appHistory = history
            return (
              <App />
            )
          }}/>
        </Router>
      </Provider>,
      document.getElementById('root')
    )
    

    然后我可以在任何我想要的地方使用 window.appHistory.push() (例如,在我的redux存储函数/ thunks / sagas等中)我曾希望我可以使用 window.customHistory.push() 但由于某种原因 react-router 似乎永远不会更新,即使网址已更改 . 但这样我就有了 react-router 使用的EXACT实例 . 我不是这样做的 . 但它已经见过IMO了 .

  • 110

    第一步将您的应用程序包装在路由器

    import { BrowserRouter as Router } from "react-router-dom";
    ReactDOM.render(<Router><App /></Router>, document.getElementById('root'));
    

    现在我的整个应用程序都可以访问BrowserRouter . 第二步我导入Route然后传递那些道具 . 可能在你的一个主要文件中 .

    import { Route } from "react-router-dom";
    
    //lots of code here
    
    //somewhere in my render function
    
        <Route
          exact
          path="/" //put what your file path is here
          render={props => (
          <div>
            <NameOfComponent
              {...props} //this will pass down your match, history, location objects
            />
          </div>
          )}
        />
    

    现在,如果我在组件js文件中运行console.log(this.props),我应该得到一些看起来像这样的东西

    {match: {…}, location: {…}, history: {…}, //other stuff }
    

    第2步我可以访问历史对象来更改我的位置

    //lots of code here relating to my whatever request I just ran delete, put so on
    
    this.props.history.push("/") // then put in whatever url you want to go to
    

    另外我只是一个编码训练营学生,所以我不是专家,但我知道你也可以使用

    window.location = "/" //wherever you want to go
    

    如果我错了,请纠正我,但是当我测试它时,它会重新加载整个页面,我认为这打败了使用React的整个过程 .

相关问题