Redux: Filtering Redux State with React Router Params

Dan Abramov
InstructorDan Abramov
Share this video with your friends

Social Share Links

Send Tweet

We will learn how adding React Router shifts the balance of responsibilities, and how the components can use both at the same time.

[00:00] I'm using the links provided by React Router now, so when I click on a link, the URL gets updated. However, the content does not get updated because the visible todo list component in its mapStateToProps function still depends on the visibility filter in the Redux store instead of reading it from the URL.

[00:20] I am adding an argument called ownProps to the mapStateToProps function, and I'm going to read the current visibility filter from ownProps. I will also change the get visible todos function to use the current convention we use for the filter prop that is all completed or active.

[00:40] The visible todo list component gets rendered from the app, so this is where we need to add the filter prop to make it available in the mapStateToProps function of the visible todo list.

[00:53] We want the filter prop to correspond to the current filter parameter in our route configuration. React Router makes such parameters available to the route handler components in a special prop called params, so I'm adding a params prop to the app, and now I can read the filter from params.filter.

[01:14] Since its empty on the root path, I'm passing all as a fallback to the visible todo list. Now I'll refresh the app, and as I press the visibility filter links, not only does the URL update, but also the console updates, even if I use back and forward buttons in the browser.

[01:36] One common problem after enabling routing is, if we go to another path and press refresh, your dev server may not be configured correctly to serve anything but the root path.

[01:48] I'm using Express with webapp-dev middleware in my development, so I just need to tell Express to serve index HTML no matter what the path is. This way, the dev server always serves the same HTML file, and React Router matches the route on the client.

[02:06] Now that the visibility filter is managed by React Router, I no longer need the visibility filter reducer. I'm just going to delete it and also remove it from the combined reducers declaration in reducers/index.js.

[02:21] Let's recap how React Router became the source of truth for the visibility filter. In the root component, I render the router, and I only have a single route with an optional filter parameter. The filter parameter gets passed into the app component by React Router. React Router will make it available inside a special params prop.

[02:46] I am passing the filter param from the URL, or all if we are on the root path, to the visible todo list component as a filter prop. The visible todo list component now reads the filter from its props and not from the state, so it uses the filter specified by the app.

[03:06] I change the get visible todos function to use the current filter names, all completed and active. For consistency, the footer component now also uses these names as the value of the filter prop for the filter link, and I re-implemented the filter link to use the link provided by React Router instead of our own implementation.

[03:30] Finally, I fix the dev server to correctly return index HTML no matter which path is requested, so that React Router can pick it up on the client.

[03:40] You might think that making the router in control of the visibility filter contradicts the idea of a single-state tree. However, in practice, what matters is that there's just one single source of truth for any independent piece of data.

[03:56] We're using Redux as the source of truth for the todos, and we're using React Router as the source of truth for anything that can be computed from the URL. In our case, this is the current visibility filter.