I would like to make use of react-router’s onEnter
handler in order to prompt users to authenticate when entering a restricted route.
So far my routes.js
file looks something like this:
import React from 'react'; import { Route, IndexRoute } from 'react-router'; export default ( <Route path="/" component={App}> <IndexRoute component={Landing} /> <Route path="learn" component={Learn} /> <Route path="about" component={About} /> <Route path="downloads" component={Downloads} onEnter={requireAuth} /> </Route> )
Ideally, I’d like my requireAuth
function to be a redux action that has access to the store and current state, that works like this: store.dispatch(requireAuth())
.
Unfortunately I don’t have access to the store in this file. I don’t think I can use really use connect
in this case to access the relevant actions that I want. I also can’t just import store
from the file where the store is created, as this is undefined when the app first loads.
Advertisement
Answer
The easiest way to accomplish this is to pass your store to a function that returns your routes (rather than return your routes directly). This way you can access the store in onEnter
and other react router methods.
So for your routes:
import React from 'react'; import { Route, IndexRoute } from 'react-router'; export const getRoutes = (store) => ( const authRequired = (nextState, replaceState) => { // Now you can access the store object here. const state = store.getState(); if (!state.user.isAuthenticated) { // Not authenticated, redirect to login. replaceState({ nextPathname: nextState.location.pathname }, '/login'); } }; return ( <Route path="/" component={App}> <IndexRoute component={Landing} /> <Route path="learn" component={Learn} /> <Route path="about" component={About} /> <Route path="downloads" component={Downloads} onEnter={authRequired} /> </Route> ); )
Then update your main component to call the getRoutes
function, passing in the store:
<Provider store={ store }> <Router history={ history }> { getRoutes(store) } </Router> </Provider>
As for dispatching an action from requireAuth
, you could write your function like this:
const authRequired = (nextState, replaceState, callback) => { store.dispatch(requireAuth()) // Assume this action returns a promise .then(() => { const state = store.getState(); if (!state.user.isAuthenticated) { // Not authenticated, redirect to login. replaceState({ nextPathname: nextState.location.pathname }, '/login'); } // All ok callback(); }); };
Hope this helps.