在React-Router v4中以编程方式导航

spi*_*k3s 32 reactjs react-router

我等不及了,我开始使用react-routerv4 的最新alpha版本.全新<BrowserRouter/>功能非常适合保持您的UI与浏览器历史记录同步,但如何使用它以编程方式进行导航?

Har*_*ood 37

路由器将historyprops哈希中向组件添加一个对象.所以在你的组件中,只需:

this.props.history.push('/mypath')

这是一个完整的例子:

App.js:

import React from 'react'
import {BrowserRouter as Router, Route} from 'react-router-dom'

import Login from './Login'

export default class App extends React.Component {
  render() {
    return (
      <Router>
        <div>
          <Route exact path='/login' component={Login} />
        </div>
      </Router>
    )
  }
}
Run Code Online (Sandbox Code Playgroud)

Login.js:

import React, {PropTypes} from 'react'

export default class Login extends React.Component {
  constructor(props) {
    super(props)
    this.handleLogin = this.handleLogin.bind(this)
  }

  handleLogin(event) {
    event.preventDefault()
    // do some login logic here, and if successful:
    this.props.history.push(`/mypath`)
  }

  render() {
    return (
      <div>
        <form onSubmit={this.handleLogin}>
          <input type='submit' value='Login' />
        </form>
      </div>
    )
  }
}
Run Code Online (Sandbox Code Playgroud)

  • 抛出错误`无法读取未定义的属性'对象',对此有何破解? (2认同)

spi*_*k3s 19

在过去,您可能习惯于browserHistory推动一条新路径.这不适用于react-routerv4.相反,你必须使用作出反应的中contextroutertransitionTo方法.

这是一个简单的例子:

import React from 'react';

class NavigateNext extends React.Component {
  constructor() {
    super();
    this.navigateProgramatically = this.navigateProgramatically.bind(this);
  }

  navigateProgramatically(e) {
    e.preventDefault();

    this.context.router.transitionTo(e.target.href)
  }

  render() {
    return (
      <Link to={"/next-page"}
            onClick={this.navigateProgramatically}
      >Continue</Link>
    );
  }
}

NavigateNext.contextTypes = {
  router: React.PropTypes.object
};
Run Code Online (Sandbox Code Playgroud)

transitionTo只是一种可用的router方法.router对象还包含blockTransitions(getPromptMessage),createHref(to)并且replaceWith(loc)这是值得一试.

这是官方react-router教程,提到了上述方法.如果你想了解更多关于使用react的信息,context请查看文档.

  • 这不适合我.我最终发现你需要的所有东西都是用`props`传递给你的组件的!你需要的只是`this.props.history.push('/ mypath')`.我在下面单独的答案中给出了一个完整的例子:http://stackoverflow.com/a/43250939/1533892 (9认同)
  • 我正在尝试这个,但上下文对象中的路由器变量是未定义的."不知何故"它是Link.js中的有效变量.知道如何在Link.js之外获取路由器对象吗? (6认同)
  • 我正在使用redux.如何从动作创建者访问路由器对象? (4认同)

小智 13

我没有足够的声誉来评论,但在回答@ singularity的问题时,您必须在组件类的contextTypes静态属性中包含您希望提供的上下文属性.

来自React文档context:

如果未定义contextTypes,则上下文将是空对象.

在这种情况下:

class NavigateNext extends React.Component {

  // ...

  static contextTypes = {
    router: PropTypes.object
  }

  // ...

}
Run Code Online (Sandbox Code Playgroud)

不同的是propTypes,contextTypes实际上导致React的行为不同,并且不仅仅是用于类型检查.


Gok*_*ari 9

使用withRouter将为您的组件添加路由器属性,然后您可以像访问v3一样访问history和使用push:

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

class Form extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      input: '',
    };

    this._submit = this._submit.bind(this);
  }

  render() {
    return (
      <form onSubmit={this._submit}>
        <input type="text" onChange={(event) => this.setState({input: event.target.value})}/>

        <button type="submit">Submit</button>
      </form>
    );
  }

  _submit(event) {
    event.preventDefault();

    this.props.history.push(`/theUrlYouWantToGoTo`);
  }
}

export default withRouter(Form);
Run Code Online (Sandbox Code Playgroud)

  • Worked like a charm, to anyone that hates React Router just as much as me, this will work ;) (3认同)

Moi*_*ain 6

react-router v4 beta发布后,API发生了一些变化.如果您使用的是最新版本this.context.router.transitionTo(e.target.href),而不是Do.this.context.router.push(e.target.href)

链接到新文档:https://reacttraining.com/react-router/#context.router

  • 我正在使用react-router-dom版本4.1.2,我使用它的唯一方法是使用`this.context.router.history.push('/')`.也许这会对某人有所帮助. (5认同)

Zap*_*ree 6

如果您需要在某个组件外部导航,而该组件位于您无法从类似于旧版本中的browserHistory组件的组件中传递历史记录对象的位置,则可以执行以下操作.

首先创建一个历史模块

History.js:

import createBrowserHistory from 'history/createBrowserHistory'

export default createBrowserHistory();
Run Code Online (Sandbox Code Playgroud)

然后当你声明路由器确保从react-router导入路由器而不是react-router-dom(它只是react-router版本的包装器但是自动创建历史对象)并传入刚创建的历史模块

Root.js(或者你在哪里这样做):

import Router from 'react-router/Router'
import history from './history'

...

class Root extends Component{
  render() {
    return (
      <Router history={history}>
        ...
      </Router>
    );
  }
}
Run Code Online (Sandbox Code Playgroud)

现在您的应用程序将使用您创建的自定义创建历史记录 您现在可以在任何地方导入该历史模块,只需执行history.replace等,就像您过去使用browserHistory一样.

SomeModule.js:

import history from './history';

export default ()=>{
  // redirecting to login page using history without having to pass it in 
  // from a component
  history.replace('/login')
}
Run Code Online (Sandbox Code Playgroud)

当然这不是推荐的方式,因为在旧版本中使用browserHistory不是推荐的方式,因为服务器端渲染之类的东西不起作用,但如果你不关心这通常是正确的解决方案.

这样做的另一个好处是你可以将历史对象扩展到解析查询字符串params这样的东西,例如:

import createBrowserHistory from 'history/createBrowserHistory'
import queryString from 'query-string';

const history = createBrowserHistory();

history.location.query = queryString.parse(history.location.search);

history.listen(() => {
  history.location.query = queryString.parse(history.location.search);
});

export default history;
Run Code Online (Sandbox Code Playgroud)


pat*_*oma 5

If you need to access history outside of components (for example in redux actions) react-router has published their original solution here.

Basically you have to create your own history object:

import { createBrowserHistory } from 'history';

const history = createBrowserHistory();
Run Code Online (Sandbox Code Playgroud)

And pass it to your router:

import { Router } from 'react-router-dom';

ReactDOM.render((
  <Router history={history}> // <<-- the history object
    <App/>
  </Router>
), document.getElementById('root'))
Run Code Online (Sandbox Code Playgroud)

Note: you have to use plain Router instead of BrowserRouter or HashRouter here!

If you export the history now, you can work with it anywhere:

import history from './history';

history.push('/home');
Run Code Online (Sandbox Code Playgroud)