Dynamic Route Configuration or: How I Learned to Stop Worrying and Love Circular Dependencies
Two big additions with this release.
Routes as children/props
Instead of passing your route configuration to the store enhancer, you now also have the option of passing it to <ReduxRouter>
as either the routes
prop or as children. This brings us in line with the normal React Router API.
Example:
ReactDOM.render((
<Provider store={store}>
<ReduxRouter>
<Route path="/" component={App}>
<Route path="parent" component={Parent}>
<Route path="child/:id" component={Child} />
</Route>
</Route>
</ReduxRouter>
</Provider>
), el);
or, equivalently:
const routes = (
<Route path="/" component={App}>
<Route path="parent" component={Parent}>
<Route path="child/:id" component={Child} />
</Route>
</Route>
);
ReactDOM.render((
<Provider store={store}>
<ReduxRouter routes={routes} />
</Provider>
), el);
This solves the circular dependency problem (#44), where if you needed a reference to the store from within a route transition hook, you had to use a closure. This was confusing and easy to mess up; the new API does this for you using React Router's built-in dynamic routes functionality.
As a bonus, the router will respond to new props, so hot reloading totally works.
Server-side rendering
To render an app on the server, import the reduxReactRouter
store enhancer from redux-react-router/server
instead of the main module. This is a slightly different version of the enhancer with server-specific functionality. Also import the match()
action creator:
import { match, reduxReactRouter } from 'redux-react-router/server';
Then set up your store like normal. You can omit createHistory
and history
if you like:
const store = compose(
applyMiddleware(m1, m2, m3),
reduxReactRouter()
)(createStore)(reducer);
The match()
action creator is very similar to the match()
function provided by React Router, except because it's an action creator, we dispatch the result. It accepts a URL and a callback:
store.dispatch(match('/some/path', (error, redirectLocation, routerState) => {
if (error) {
// handle error
}
if (redirectLocation) {
// handle redirect
}
if (!routerState) {
// handle 404
}
// Otherwise, render to string
res.send(
renderToString(
<Provider store={store}>
<Route path="/" component={App}>
<Route path="some" component={Parent}>
<Route path="path" component={Child} />
</Route>
</Route>
</Provider>
)
);
}));