How to use React Router's redirect function?
EDIT See other answer for new, non-deprecated react-router syntax
There's a good example of how to use the onEnter
hook in the auth-flow example. Here's the relevant code:
function requireAuth(nextState, replaceState) { if (!auth.loggedIn()) replaceState({ nextPathname: nextState.location.pathname }, '/login')}render(( <Router history={history}> <Route path="/" component={App}> <Route path="login" component={Login} /> <Route path="logout" component={Logout} /> <Route path="about" component={About} /> <Route path="dashboard" component={Dashboard} onEnter={requireAuth} /> </Route> </Router>), document.getElementById('example'))
As you can see, when the /dashboard
route is accessed the requireAuth
function is called. It receives two arguments: nextState
, which is a RouterState
object that represents the state the user is about to enter, and replaceState
, a RedirectFunction
that can be called to replace that state with something else. In this case, if the user isn't logged in, requireAuth
calls replaceState
like this:
replaceState({ nextPathname: nextState.location.pathname }, '/login')
The second argument is obviously the pathname the user will be redirected to. The very first argument is an object that can contain any data we want the route handler (in this case the Login
component) to have. Here the pathname the user was trying to go to (/dashboard
) is set as the nextPathname
property so after logging in the user can be redirected to that page (see the handleSubmit
method in the Login
component).
If the user is logged in, requireAuth
does nothing, and since replaceState
is never called the route works as usual, which is to say the Dashboard
component is rendered.
Heads up to anyone reading this question as of react-router 2.0.0, replaceState(state, pathname, query) is now deprecated. You must now use replace(location) with a location descriptor instead.
From their guide:
// v1.0.x(nextState, replaceState) => replaceState(null, '/foo')(nextState, replaceState) => replaceState(null, '/foo', { the: 'query' })// v2.0.0(nextState, replace) => replace('/foo')(nextState, replace) => replace({ pathname: '/foo', query: { the: 'query' } })
Here is an example of how to do this with react-router
2.0.0 (using replace
instead of replaceState
):
In router.jsx:
function requireAuth(nextState, replace) { if (!userExists()) { replace({ pathname: '/signin', state: { nextPathname: nextState.location.pathname } }) }}export const renderRoutes = () => ( <Router history={browserHistory}> <Route path="protectedRoute" component={Protected} onEnter={requireAuth} /> <Route path="signin" component={SignIn} /> </Route> </Router>);
Then, inside SignIn
component, you can redirect after a successful sign in like this:
import { browserHistory } from 'react-router';signInFunction({params}, (err, res) => { // Now in the sign in callback if (err) alert("Please try again") else { const location = this.props.location if (location.state && location.state.nextPathname) { browserHistory.push(location.state.nextPathname) } else { browserHistory.push('/') } }})