Oftentimes in a Redux application we have a little bit of state that we’d like to be made re-usable. By state, I don’t just mean the structure of some object, I’m also referring to the management of that state. This tends to happen as your application grows and then a requirement comes in to do something similar to what you’ve done previously. Very often you’ll already have a nice bit of code that you’d like to re-use.
This recently happened to me, so I’d like to document how I go about making reducers re-usable in large-scale applications. Firstly, a brief recap.
What’s a Reducer?
Recall that Redux applications contain a state object. The way that this state is modified is via a simple function:
nextState = update(prevState, action)
An action is typically an object with an identifying
type property and a
payload. The type name takes the form of a unique String. A sample action looks like this:
update function is reducing the old state and the action into a new state object, which is why it’s known as a reducer function. What you’re actually wanting to re-use, therefore, are three things:
- The state model - the structure of the object corresponding to some application state
- Some actions - which define how the state can be mutated
- A reducer - which will perform the mutation on your state
A create Reducer function
What I normally do is have a function which, when called, returns a reducer function. This can then be included in your reducer tree via a
combineReducers call. In terms of actions - we need a unique name. To achieve this, the function accepts an
actionRoot argument - it’s just a string! Internally, the function creates some action strings by prepending this value to each action name. This makes them unique, but within the function, they can be reference by their variable names (in this case:
DECREMENT). The action names are also returned too, in case they’re needed elsewhere.
This is how this looks:
Now, wherever we wish to use this state model, we can simply call the function!
In this example, I’m using the
redux-actions library to create action creator functions based on the actions returned by my
createReducer function, so that when called, they return a standard action object of that type. These can now be used in a redux
Connected component via its
mapDispatchToProps function - let’s say so that when a user clicks a button, either my
DECREMENT action is dispatched. I’m also returning the reducer so that it can be included in the state tree.
You’ll have probably noticed that this concept is very similar in nature to what I discussed in my article on Higher-Order Reducers, and in yesterday’s article on reusing Redux Form components. This shows the fantastic utility of composition!
As an application grows, you’ll find yourself wanting to handle certain things in common ways - the state model for network requests, dialogs, and so on. This technique is a handy way of creating small modules that are ripe for re-use across your application. With this technique put in practice, you’ll become familiarised with a common state model, and see a common set of actions that conform to a pattern in your dispatched action log.
Redux application states can become complicated to reason about. Reducing the cognitive overhead in doing so is imperative as your application grows in size and complexity. Overall, I think that this is an incredibly useful way of bringing down the cost of maintenance in a large-scale Redux project.