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="https://stackoverflow.com/" 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.