This blog post is part of a series of blog posts. You can find part 1 of the series here
Welcome to the second part of a series of blog posts that summarize the workshop on Redux held by Dan Abramov and Andrew Clark at React Europe 2016. In this blog post we’ll go through the remaining four exercises of the first day of the workshop and I’ll add both the exercise as well as the solutions. I try to annotate the solutions heavily and also, when needed, reason about the code and underlying principles as well. Since the exercises from here on out more or less build upon the previous ones, you might want to go back and read the first part of the series. So let’s get cracking!
Exercise 5 – Reducer composition with arrays
Since Redux constrains you to a single store and the createStore()
function accepts only a single reducer, it is a vital skill to know how to split your single reducer into different parts. We all know that separation of concerns is really important and when it comes to your Redux reducer it really is not any different. A reducer that does too much quickly becomes hard to comprehend and reason about. In exercise 5 we practice on how to do this for arrays:
As you can see in the exercise, our todos
-reducer is doing too much work. It manages both the array of todo items, as well as managing individual todo items. This means that it is a prime candidate for refactoring and composition. Our goal is to split this reducer into two reducers, where each reducer has its own responsibility. So what we are aiming for here is to let our parent reducer (the todos
reducer) manage only the array by adding and delegating actions. The new todo
child reducer will contain all logic of how a single todo item is created and updated.
Now isn’t that nicer? After this refactoring each of the reducers has a clearly defined responsibility. If a bug is discovered in how todo items are added or updated, it is now easier to find the source of the problem. Are fields not added or updated correctly? – You’ve probably got a bug in the todo
-reducer. Are todo-items not added correctly? – Look for the bug in the todos
-reducer.
Exercise 6 – Reducer composition with objects
Of course, not only reducers that manage arrays can be split into hierarchies. Reducers that manage objects can also be split. If you take this a bit further, you’ll soon have a tree hierarchy of reducers, much like you’ve got a hierarchy of components to display your data in React. Out of the box Redux provides us with combineReducers()
to do this in a simple way. But as we’ll see, there is no black magic going on in that function and if you have more complex needs you can compose the reducers manually or write some helper function that will do it for you.
The first part of the exercise is very straightforward if you’ve used Redux before. The visibilityFilter
reducer handles only a single action and combineReducers()
is exported as a named top level export of Redux:
In the first optional task we are asked to manually compose our two top-level reducers. Remember that reducer composition is all about separation of concern, so a manual composition is just another reducer that delegates updating substate to the reducers lower in the hierarchy.
As you can see, a manual composition is quite simple. Our parent reducer puts each of the child reducers into an object, where each key holds the state of that reducer. For each action we receive, we simply call each child reducer with its slice of the state and the action and return a new object with the exact same shape. This is exactly what combineReducers
provides us with. Given that knowledge, re-implementing combineReducers
is straightforward:
Of course, in a production-worthy implementation of combineReducers
you would need to add error checking and friendly error messages to ensure the function is used as intended. But basically, that is it! No black magic, nothing too complex, just keeping track of the state for each of the reducers and make sure we delegate the decision of how to handle a specific action to them.
The astute reader might notice that on line 25, don’t we mutate the state there? Yes, we actually do. But it is the new state which is a new object that so far has never been exposed to anything else. If we wanted to be really hard-core about immutability we could of course create a new object for each reducer we are combining, and for each reducer create a copy of the previous state, add the next property and so on. But it would be terribly inefficient and not actually gain us anything. What is important is that a previous state is never modified after it has been returned from the reducer. And also, if we mutate the new object here internally, and no one ever knows about it, has it really happened?
Exercise 7 – Building a Todo App with Presentational Components
Time to add some more React into the mix! In exercise 7 we’re asked to build a simple interface for out todo app. It won’t be pretty, but it will be functional. In fact, it will be so functional that we will create it using only stateless functional components. (See what I did there? Pun totally intended.)
Stateless functional components were introduced in React 0.14 and are great for creating your presentational components that do not, as the name implies, have their own internal state. If you are not using them yet, you really should look into them!
Read more in the blog post announcement of React 0.14 or in the React documentation
Since the solution to this exercise is just JSX, I’ll just post the solution. When warranted, comments are inlined in the code.
Exercise 8 – Using connect
One final step left before we can call it a day, we should remove the subscription to the store and instead connect our components using Redux. While the solution from exercise 7 certainly works, it is also inefficient, since any update to the store will cause a complete re-render of our app. By connecting our components at appropriate places in the view tree, we can reduce the amount of work we need to do drastically. We can also avoid having to declare properties in parent components, that we are not really interested in, just so we can pass them down to children who needs them to render properly. So, here is the exercise outline:
Let’s tackle the problems one by one. First up, splitting FilterLink
into Link
and a new, connected, version of FilterLink
.
We’ll see later how we can make use of the new connected version of FilterLink
to simplify our Footer
-component. Next up, we’ll connect our TodoList
:
We’re getting close to a fully connected and working version now! Next up is `AddTodo` that used to get a callback as a property. By connecting this component we can utilize dispatch
to send an action directly to the Redux store, which simplifies usage of this component:
The only thing that remains now is to update our components to use the connected versions. We will also remove the explicit top level subscription that re-renders the whole component tree, and instead let the connected components decide if they need to re-render when the state updates:
So, that’s it! We’re now using Redux to keep track of the state of our application and we have connected our components to ensure we re-render the parts of our UI that changes as our application state updates.
Conclusion of day 1
Congratulations for making it this far! This concludes day 1 of the workshop on Redux held by Dan Abramov and Andrew Clark. Stay tuned for a summary of day 2.
More in this series
- Part 1
- Part 2
- Upcoming: Workshop on Redux by Dan Abramov and Andrew Clark – Day 2