How to use reducers in a React application
We have seen that a reducer is a function that takes a state object and an action
object and returns a new state
object modifying the state that was received based on the action.
It's important to notice that the state
object returned by the reducer is a completely new object. The reducer doesn't modify the state that was passed in.
The reducer takes the state that was passed in, and from that state it creates a new object that incorporates changes based on the action argument.
Another point of note about reducers is that they will be called with different actions as arguments.
For example, the titleReducer
could be called with an action named UPDATE_TITLE
and also with another action called TURN_TITLE_GREEN
.
We don't know beforehand which action will be passed in, so, inside the reducer, we need to have a way to run different code based on which action matches.
This means we need to have a conditional: if this action comes in, do this. If this other action comes in, do that.
We could use if
statements as conditionals, but for code clarity it's common to use switch
statements inside a reducer.
A switch
statement checks if a condition is true and runs the appropriate branch.
Here's a reducer with three different outputs based on the action. If the action is TURN_TITLE_GREEN
, the first case statement is executed. If the action UPDATE_TITLE
comes in, the second case statement is executed.
If the action that comes in doesn't match any of our case statements, the default statement at the bottom is executed and the state
is returned unchanged.
const titleReducer = (state = initialState, action) => {
switch (action.type) {
case TURN_TITLE_GREEN: {
return {
...state,
titleColor: 'green'
}
}
case UPDATE_TITLE: {
return {
...state,
title: action.payload
}
}
default: return state;
}
}
Actions that come into a reducer are objects with a type
and an optional payload
properties.
The type
property is mandatory, and determines the action type (TURN_TITLE_GREEN
, UPDATE_TITLE
, and so on).
The payload
property is optional but if it exists it contains information on how to change the state.
In the case
statement below, we use the action payload to set a new title on the state. action.payload
here holds a string with the updated title:
case UPDATE_TITLE: {
return {
...state,
title: action.payload
}
Also, note how we return a brand new object. In the new object we use the spread
operator (...
) to add the original state and after that we modify only the property affected by this particular action.
This shows that we are not modifying the state directly, we are just copying the old state into a new object, then we modify the new object, and then we return it leaving the original state unchanged.
Tomorrow we will take a look at actions and we'll see how they are structured.
I write daily about web development. If you like this article, feel free to share it with your friends and colleagues.
You can receive articles like this in your inbox by subscribing to my newsletter.
Top comments (0)