react-router
is the de-facto standard routing solution for react applications.
The thing is that with redux and a single state tree, the URL is part of that
state. react-router-redux
takes care of synchronizing the location of our
application with the application state.
(See the react-router-redux
documentation
for more information)
To add a new route, use the generator with npm run generate route
.
This is what a standard (generated) route looks like for a container:
{
path: '/',
name: 'home',
getComponent(nextState, cb) {
const importModules = Promise.all([
System.import('containers/HomePage')
]);
const renderRoute = loadModule(cb);
importModules.then(([component]) => {
renderRoute(component);
});
importModules.catch(errorLoading);
},
}
To go to a new page use the push
function by react-router-redux
:
import { push } from 'react-router-redux';
dispatch(push('/some/page'));
npm run generate route
does not currently support automatically generating child routes if you need them, but they can be easily created manually.
For example, if you have a route called about
at /about
and want to make a child route called team
at /about/our-team
you can just add that child page to the parent page's childRoutes
array like so:
/* your app's other routes would already be in this array */
{
path: '/about',
name: 'about',
getComponent(nextState, cb) {
const importModules = Promise.all([
System.import('containers/AboutPage'),
]);
const renderRoute = loadModule(cb);
importModules.then(([component]) => {
renderRoute(component);
});
importModules.catch(errorLoading);
},
childRoutes: [
{
path: '/about/our-team',
name: 'team',
getComponent(nextState, cb) {
const importModules = Promise.all([
System.import('containers/TeamPage'),
]);
const renderRoute = loadModule(cb);
importModules.then(([component]) => {
renderRoute(component);
});
importModules.catch(errorLoading);
},
},
]
}
To go to a dynamic route such as 'post/:slug' eg 'post/cool-new-post', firstly add the route to your routes.js
, as per documentation:
path: '/posts/:slug',
name: 'post',
getComponent(nextState, cb) {
const importModules = Promise.all([
System.import('containers/Post/reducer'),
System.import('containers/Post/sagas'),
System.import('containers/Post'),
]);
const renderRoute = loadModule(cb);
importModules.then(([reducer, sagas, component]) => {
injectReducer('post', reducer.default);
injectSagas(sagas.default);
renderRoute(component);
});
importModules.catch(errorLoading);
},
###Container:
<Link to={`/posts/${post.slug}`} key={post._id}>
Clickable link with payload (you could use push if needed).
###Action:
export function getPost(slug) {
return {
type: LOAD_POST,
slug,
};
}
export function postLoaded(post) {
return {
type: LOAD_POST_SUCCESS,
podcast,
};
}
###Saga:
const { slug } = yield take(LOAD_POST);
yield call(getXhrPodcast, slug);
export function* getXhrPodcast(slug) {
const requestURL = `http://your.api.com/api/posts/${slug}`;
const post = yield call(request, requestURL);
if (!post.err) {
yield put(postLoaded(post));
} else {
yield put(postLoadingError(post.err));
}
}
Wait (take
) for the LOAD_POST constant, which contains the slug payload from the getPost()
function in actions.js.
When the action is fired then dispatch the getXhrPodcast()
function to get the response from your api. On success dispatch the postLoaded()
action (yield put
) which sends back the response and can be added into the reducer state.
You can read more on react-router
's documentation.