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, because the thing I'm exporting is not a component. I also can't just import store from the file where the store is created, as this is undefined when the app first loads.
@Robinnnnn I have similar need that I want to access store in onEnter. How did you solve your problem?
hey @jungejason, I just decided to pass down the store as props into the component that was generating my routes. Here is my code, in full:
import React, {PropTypes} from 'react';
import {Provider} from 'react-redux';
import {Router, browserHistory, Route, IndexRoute, Redirect} from 'react-router';
import {syncHistoryWithStore} from 'react-router-redux';
import App from './components/App';
import Landing from './components/routes/public/Landing';
import Prospect from './components/routes/public/Prospect';
import Mobile from './components/routes/public/Mobile';
import { Learn } from './components/routes/public/Learn';
import { About } from './components/routes/public/About';
import OpenPositions from './components/routes/public/Careers/OpenPositions';
import Job from './components/routes/public/Careers/Job';
import Downloads from './components/routes/restricted/Downloads';
import ResetPassword from './components/routes/public/ResetPassword';
import PanoLibrary from './components/routes/restricted/PanoLibrary';
import NoMatch from './components/routes/public/NoMatch';
import Project from './components/routes/restricted/PanoLibrary/Project';
import {requireAuth} from './actions/auth/requireAuth';
export default class Root extends React.Component {
render() {
const { store } = this.props; // *** passed here from the parent component.
const history = syncHistoryWithStore(browserHistory, store)
// here is the function that is triggered onEnter
const requireAuthentication = (nextState, replace) => {
store.dispatch(requireAuth(nextState, replace, store));
}
return (
<div>
<Provider store={store}>
<Router history={history}>
<Route path="/" component={App} >
<IndexRoute component={Landing} />
<Route path="prospect" component={Prospect} />
<Route path="mobile" component={Mobile} />
<Route path="learn" component={Learn} />
<Route path="about" component={About} />
<Route path="jobs">
<IndexRoute component={OpenPositions}/>
<Route path=":id" component={Job} />
</Route>
<Route path="downloads" component={Downloads} onEnter={requireAuthentication}/>
<Route path="panos" component={PanoLibrary} onEnter={requireAuthentication} >
<IndexRoute component={Project}/>
</Route>
<Route path="reset-password/:token" component={ResetPassword}/>
<Route path="nomatch" component={NoMatch} />
<Redirect from="*" to="nomatch"/>
</Route>
</Router>
</Provider>
</div>
)
}
}
And here is the parent file:
import React from 'react';
import { render } from 'react-dom';
import Root from './Root';
import { configureStore } from './store';
import { storeInitialLocation, examineLocalStorage } from './actions';
export const store = configureStore(window.__INITIAL_STATE__);
render(
// passing the store down to the component that renders my routes
<Root store={store} />,
document.getElementById('app')
)
Thank you @Robinnnnn!!
Alternatively you can change your routes.js to export a function like getRoutes(store) and pass it there.
Thank you @gaearon!! It's nice to be able to still have routes in a separated file.
BTW, I really like your Redux training on egghead.io. I really enjoy the way you describe the idea, then do a simple implementation, and then finally add layers of abstractions at the end. It's the best training video I've seen in the last several years. Thank you!
@jungejason Thank you for kind words!
The ability to abstract routes.js is super helpful.
On another note, I side with @jungejason -- thank you for all that you do @gaearon, your egghead videos are the reason I decided to migrate our web stack to React + Redux and away from Angular. I'm a much happier person now :)
Most helpful comment
Thank you @gaearon!! It's nice to be able to still have
routesin a separated file.BTW, I really like your Redux training on egghead.io. I really enjoy the way you describe the idea, then do a simple implementation, and then finally add layers of abstractions at the end. It's the best training video I've seen in the last several years. Thank you!