Reactjs 如何在React Router v4中推送历史?

Reactjs 如何在React Router v4中推送历史?,reactjs,react-router,react-router-v4,Reactjs,React Router,React Router V4,在当前版本的React Router(v3)中,我可以接受服务器响应并使用browserHistory.push进入相应的响应页面。然而,这在v4中是不可用的,我不确定处理这个问题的合适方法是什么 在本例中,当用户提交表单时,components/app-product-form.js使用Redux调用this.props.addProduct(props)。当服务器返回成功时,用户被带到购物车页面 // actions/index.js export function addProduct(p

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

在本例中,当用户提交表单时,components/app-product-form.js使用Redux调用
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的函数重定向到购物车页面?

React Router v4与v3(及更早版本)有根本不同,您无法像以前那样执行
browserHistory.push()

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

  • 创建一个新的
    browserHistory
    将不起作用,因为
    创建自己的历史实例,并侦听该实例上的更改。因此,另一个实例将更改url,但不会更新
  • browserHistory
    不会被v4中的react路由器公开,只在v2中公开

相反,您有几个选项可以执行此操作:

  • 与路由器一起使用
    高阶组件 相反,您应该使用
    with router
    高阶组件,并将其包装到将推送到历史的组件。例如:

    从“React”导入React;
    从“react router dom”导入{withRouter};
    类MyComponent扩展了React.Component{
    ...
    myFunction(){
    this.props.history.push(“/some/Path”);
    }
    ...
    }
    使用路由器导出默认值(MyComponent);
    
    查看以了解更多信息:

    您可以通过withRouter高阶组件访问对象的属性和最近的属性。withRouter将在每次路由更改时使用与渲染道具相同的道具重新渲染其组件:
    {match,location,history}


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

    从“React”导入React;
    从“道具类型”导入道具类型;
    类MyComponent扩展了React.Component{
    静态上下文类型={
    路由器:PropTypes.object
    }
    构造函数(道具、上下文){
    超级(道具、背景);
    }
    ...
    myFunction(){
    this.context.router.history.push(“/some/Path”);
    }
    ...
    }
    
    请看一下上下文:

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

    如果您不顾这些警告仍坚持使用上下文,请尝试将上下文的使用限制在一个小范围内,尽可能避免直接使用上下文API,以便在API更改时更容易升级

    • 我就是这样做的:

      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>
              );
          }
      }
      
      import React,{Component}来自'React';
      导出默认类链接扩展组件{
      建造师(道具){
      超级(道具);
      this.onLogout=this.onLogout.bind(this);
      }
      onLogout(){
      this.props.history.push('/');
      }
      render(){
      返回(
      你的链接
      注销
      );
      }
      }
      
      使用
      this.props.history.push('/cart')要重定向到购物车页面,它将保存在历史对象中


      享受吧,迈克尔。

      这个.context.history.push将不起作用

      我设法让push这样工作:

      static contextTypes = {
          router: PropTypes.object
      }
      
      handleSubmit(e) {
          e.preventDefault();
      
          if (this.props.auth.success) {
              this.context.router.history.push("/some/Path")
          }
      
      }
      
      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>
        );
      }
      
      如果您使用的是Redux,那么我建议您使用npm包。它允许您分派Redux商店导航操作

      您必须按照他们的说明创建存储

      最简单的用例:

      从'react router redux'导入{push}
      这个.props.dispatch(push(“/第二页”);
      
      容器/组件的第二个用例:

      容器:

      从'react redux'导入{connect};
      从“react router redux”导入{push};
      从“../components/Form”导入表单;
      const mapDispatchToProps=调度=>({
      changeUrl:url=>dispatch(推送(url)),
      });
      导出默认连接(空,mapDispatchToProps)(表单);
      
      组成部分:

      onClick={() => {
        this.props.actionCreatorName(
          this.props.history,
          otherParams
        );
      }}
      
      import React,{Component}来自'React';
      从“道具类型”导入道具类型;
      导出默认类表单扩展组件{
      handleClick=()=>{
      this.props.changeUrl('/secondPage');
      };
      render(){
      返回(
      自述文件
      );
      }
      }
      
      在这种情况下,您将道具传递给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')
          })
        }
      }
      

      需要深度整合以:

      “能够通过分派操作进行导航”

      但是,他们建议将此方法作为“深度集成”的替代方案:

      “您可以将提供用于将组件路由到您的操作的历史对象传递到您的操作并在其中导航,而不是分派操作进行导航。”

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

      exportdefaultwithrouter(connect(null,{actionCreatorName})(ReactComponent))

      将历史API传递给道具。因此,您可以调用作为参数传递历史记录的动作创建者。例如,在组件内部:

      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");
        };
      }
      
      这是我的黑客攻击(这是我的根级别文件,其中混合了一些redux-尽管我没有使用
      react router redux
      ):

      const store=configureStore()
      const customHistory=createBrowserHistory({
      basename:config.urlBasename | |“”
      })
      ReactDOM.render(
      {
      window.appHistory=历史记录
      返回(
      )
      }}/>
      ,
      document.getElementById('root'))
      )
      
      然后我可以使用
      窗口
      
      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));
      
      import createHistory from 'history/createBrowserHistory'
      const history = createHistory()
      history.pushLater = (...args) => setImmediate(() => history.push(...args))
      export default history
      
      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>
          )
         }
        }
      
      import history from './history'
      export const login = createAction(
      ...
      history.pushLater({ pathname: PATH_REDIRECT_LOGIN })
      ...)
      
      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
      
      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")
                  }
              })
      }
      
      import React from "react"
      
      const Success = () => {
          return (
              <div className="Success">
                  Hey cool, got it.
              </div>
          )
      }
      
      export default Success
      
      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>
      
      )
      
      /*Step 1*/
      myFunction(){  this.props.history.push("/home"); }
      /**/
       <button onClick={()=>this.myFunction()} className={'btn btn-primary'}>Go 
       Home</button>
      
      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'))
      
      import { BrowserRouter as Router } from "react-router-dom";
      ReactDOM.render(<Router><App /></Router>, document.getElementById('root'));
      
      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>
            )}
          />
      
      {match: {…}, location: {…}, history: {…}, //other stuff }
      
      //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
      
      this.props.history.push("/dummy",value)
      
      this.props.history.push('/new/url');
      
      <Route path="/profile" component={ViewProfile}/>
      
      <Route path="/users" render={() => <ViewUsers/>}
      
      <Route path="/users" render={props => <ViewUsers {...props} />}
      
      import * as React from 'react';
      import { Redirect } from 'react-router-dom';
      class Example extends React.Component {
        componentDidMount() {
          this.setState({
            redirectTo: '/test/path'
          });
        }
      
        render() {
          const { redirectTo } = this.state;
      
          return <Redirect to={{pathname: redirectTo}} push={true}/>
        }
      }
      
      import React from 'react';
      import { Router } from 'react-router-dom';
      import { createBrowserHistory } from 'history';
      
      export const history = createBrowserHistory();
      
      const ExtBrowserRouter = ({children}) => (
        <Router history={history} >
        { children }
        </Router>
      );
      
      export default ExtBrowserRouter
      
      import React from 'react';       
      import { /*BrowserRouter,*/ Route, Switch, Redirect } from 'react-router-dom';
      
      //Use 'ExtBrowserRouter' instead of 'BrowserRouter'
      import ExtBrowserRouter from './ExtBrowserRouter'; 
      ...
      
      export default class Root extends React.Component {
        render() {
          return (
            <Provider store={store}>
              <ExtBrowserRouter>
                <Switch>
                  ...
                  <Route path="/login" component={Login}  />
                  ...
                </Switch>
              </ExtBrowserRouter>
            </Provider>
          )
        }
      }
      
      import { history } from '../routers/ExtBrowserRouter';
      ...
      
      export function logout(){
        clearTokens();      
        history.push('/login'); //WORKS AS EXPECTED!
        return Promise.reject('Refresh token has expired');
      }
      
      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>
        );
      }
      
          <Route path='/create' render={({history}) => (
            <YourComponent
              YourProp={() => {
                this.YourClassMethod()
                history.push('/')
              }}>
            </YourComponent>
          )} />
      
      import { useHistory } from "react-router-dom";
      import { useDispatch } from "react-redux";
      
      const Component = () => {
        ...
        const history = useHistory();
        dispatch(myActionCreator(otherValues, history));
      };
      
      
      const myActionCreator = (otherValues, history) => async (dispatch) => {
        ...
        history.push("/path");
      }