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

使用 react-router 我可以使用 Link 元素来创建由 react 路由器本地处理的链接。

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

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

我看到了 Navigation mixin,但是没有 mixins 我可以这样做吗?

React Router v5.1.0 with hooks

There is a new useHistory hook in React Router >5.1.0 if you are using React >16.8.0 and functional components.

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

With v4 of React Router, there are three approaches that you can take to programmatic routing within components.

  1. Use the withRouter higher-order component.
  2. Use composition and render a <Route>
  3. Use the context.

React Router is mostly a wrapper around the history library. history handles interaction with the browser's window.history for you with its browser and hash histories. It also provides a memory history which is useful for environments that don't have a global history. This is particularly useful in mobile app development (react-native) and unit testing with Node.

A history instance has two methods for navigating: push and replace. If you think of the history as an array of visited locations, push will add a new location to the array and replace will replace the current location in the array with the new one. Typically you will want to use the push method when you are navigating.

In earlier versions of React Router, you had to create your own history instance, but in v4 the <BrowserRouter>, <HashRouter>, and <MemoryRouter> components will create a browser, hash, and memory instances for you. React Router makes the properties and methods of the history instance associated with your router available through the context, under the router object.

1. Use the withRouter higher-order component

The withRouter higher-order component will inject the history object as a prop of the component. This allows you to access the push and replace methods without having to deal with the 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. Use composition and render a <Route>

The <Route> component isn't just for matching locations. You can render a pathless route and it will always match the current location. The <Route> component passes the same props as withRouter, so you will be able to access the history methods through the history prop.

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

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

3. Use the context*

But you probably should not

The last option is one that you should only use if you feel comfortable working with React's context model (React's Context API is stable as of 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 and 2 are the simplest choices to implement, so for most use cases, they are your best bets.

Here's how you do this with react-router v2.0.0 with ES6. react-router has moved away from mixins.

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
}

</div>

For ES6 + React components, the following solution worked for me.

I followed Felippe skinner, but added an end to end solution to help beginners like me.

Below are the versions I used:

"react-router": "^2.7.0"

"react": "^15.3.1"

Below is my react component where I used programmatic navigation using react-router:

import React from 'react';

class loginComp extends React.Component {
constructor( context) {
super(context);
this.state = {
uname: ‘’,
pwd: ‘’
};
}

redirectToMainPage(){
this.context.router.replace(’/home’);
}

render(){
return <div>
// skipping html code
<button onClick={this.redirectToMainPage.bind(this)}>Redirect</button>
</div>;
}
};

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

module.exports = loginComp;

Below is the configuration for my router:

 import { Router, Route, IndexRedirect, browserHistory } from 'react-router'

render(<Router history={browserHistory}>
<Route path=’/’ component={ParentComp}>
<IndexRedirect to = “/login”/>
<Route path=’/login’ component={LoginComp}/>
<Route path=’/home’ component={HomeComp}/>
<Route path=’/repair’ component={RepairJobComp} />
<Route path=’/service’ component={ServiceJobComp} />
</Route>
</Router>, document.getElementById(‘root’));


With the current React version (15.3), this.props.history.push('/location'); worked for me, but it showed the following warning:

browser.js:49 Warning: [react-router] props.history and context.history are deprecated. Please use context.router.

and I solved it using context.router like this:

import React from 'react';

class MyComponent extends React.Component {

constructor(props) {
    super(props);
    this.backPressed = this.backPressed.bind(this);
}

backPressed() {
    this.context.router.push('/back-location');
}

...

}

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

export default MyComponent;

</div>