{"id":297101,"date":"2019-10-24T07:21:52","date_gmt":"2019-10-24T14:21:52","guid":{"rendered":"https:\/\/css-tricks.com\/?p=297101"},"modified":"2019-10-24T07:30:18","modified_gmt":"2019-10-24T14:30:18","slug":"understanding-how-reducers-are-used-in-redux","status":"publish","type":"post","link":"https:\/\/css-tricks.com\/understanding-how-reducers-are-used-in-redux\/","title":{"rendered":"Understanding How Reducers are Used in Redux"},"content":{"rendered":"
A reducer is a function<\/strong> that determines changes<\/strong> to an application\u2019s state.<\/strong> It uses the action<\/strong> it receives to determine this change. We have tools, like Redux<\/a>, that help manage an application\u2019s state changes in a single store so that they behave consistently.<\/p>\n Why do we mention Redux when talking about reducers? Redux relies heavily on reducer functions that take the previous state and an action in order to execute the next state.<\/p>\n We\u2019re going to focus squarely on reducers is in this post. Our goal is to get comfortable working with the reducer function so that we can see how it is used to update the state of an application \u2014 and ultimately understand the role they play in a state manager, like Redux.<\/p>\n <\/p>\n State changes are based on a user\u2019s interaction, or even something like a network request. If the application\u2019s state is managed by Redux, the changes happen inside a reducer function \u2014 this is the only place where state changes happen. The reducer function makes use of the initial state<\/strong> of the application and something called action<\/strong>, to determine what the new state<\/strong> will look like.<\/p>\n If we were in math class, we could say:<\/p>\n In terms of an actual reducer function, that looks like this:<\/p>\n Where do we get that initial state and action? Those are things we define.<\/p>\n The Let\u2019s say the initial state of our app is an empty list of contacts and our action is adding a new contact to the list.<\/p>\n That creates our An There is typically a The state is meant to be In the above example, we made use of the To make use of The alternative to This ensures that the incoming state stays intact as we append the new item to the bottom.<\/p>\n Earlier, we noted that the update that happens depends on the value of That means that a typical reducer will look like this:<\/p>\n It\u2019s important that we return state our Since we don\u2019t have this kind of action type, we\u2019ll want to return what we have in the state (the current state of the application) instead. All that means is we\u2019re unsure of what the user is trying to achieve at the moment.<\/p>\n Here\u2019s a simple example of how I implemented the reducer function in React.<\/p>\n \n See the Pen You can see that I didn\u2019t make use of Redux, but this is very much the same way Redux uses reducers to store and update state changes. The primary state update happens in the reducer function, and the value it returns sets the updated state of the application.<\/p>\n Want to give it a try? You can extend the reducer function to allow the user to update the age of a contact. I\u2019d like to see what you come up with in the comment section!<\/p>\nWhat we mean by \u201cstate\u201d<\/h3>\n
initial state + action = new state<\/code><\/pre>\n
const contactReducer = (state = initialState, action) => {\r\n \/\/ Do something\r\n}<\/code><\/pre>\n
The state parameter<\/h3>\n
state<\/code> parameter that gets passed to the reducer function has to be the current state of the application. In this case, we\u2019re calling that our
initialState<\/code> because it will be the first (and current) state and nothing will precede it.<\/p>\n
contactReducer(initialState, action)<\/code><\/pre>\n
const initialState = {\r\n contacts: []\r\n}<\/code><\/pre>\n
initialState<\/code>, which is equal to the
state<\/code> parameter we need for the reducer function.<\/p>\n
The action parameter<\/h3>\n
action<\/code> is an object that contains two keys and their values. The state update that happens in the reducer is always dependent on the value of
action.type<\/code>. In this scenario, we are demonstrating what happens when the user tries to create a new contact. So, let\u2019s define the
action.type<\/code> as
NEW_CONTACT<\/code>.<\/p>\n
const action = {\r\n type: 'NEW_CONTACT',\r\n name: 'John Doe',\r\n location: 'Lagos Nigeria',\r\n email: 'johndoe@example.com'\r\n}<\/code><\/pre>\n
payload<\/code> value that contains what the user is sending and would be used to update the state of the application. It is important to note that
action.type<\/code> is required, but
action.payload<\/code> is optional. Making use of
payload<\/code> brings a level of structure to how the action object looks like.<\/p>\n
Updating state<\/h3>\n
immutable<\/code>, meaning it shouldn\u2019t be changed directly. To create an updated state, we can make use of
Object.assign<\/a><\/code> or opt for the spread operator<\/a>.<\/p>\n
Object.assign<\/h4>\n
const contactReducer = (state, action) => {\r\n switch (action.type) {\r\n case 'NEW_CONTACT':\r\n return Object.assign({}, state, {\r\n contacts: [\r\n ...state.contacts,\r\n action.payload\r\n ]\r\n })\r\n default:\r\n return state\r\n }\r\n}<\/code><\/pre>\n
Object.assign()<\/code> to make sure that we do not change the state value directly. Instead, it allows us to return a new object which is filled with the state that is passed to it and the payload sent by the user.<\/p>\n
Object.assign()<\/code>, it is important that the first argument is an empty object. Passing the state as the first argument will cause it to be mutated, which is what we\u2019re trying to avoid in order to keep things consistent.<\/p>\n
The spread operator<\/h4>\n
object.assign()<\/code> is to make use of the spread operator, like so:<\/p>\n
const contactReducer = (state, action) => {\r\n switch (action.type) {\r\n case 'NEW_CONTACT':\r\n return {\r\n ...state, contacts:\r\n [...state.contacts, action.payload]\r\n }\r\n default:\r\n return state\r\n }\r\n}<\/code><\/pre>\n
Working with a switch statement<\/h3>\n
action.type<\/code>. The switch statement conditionally determines the kind of update we’re dealing with, based on the value of the
action.type<\/code>.<\/p>\n
const addContact = (state, action) => {\r\n switch (action.type) {\r\n case 'NEW_CONTACT':\r\n return {\r\n ...state, contacts:\r\n [...state.contacts, action.payload]\r\n }\r\n case 'UPDATE_CONTACT':\r\n return {\r\n \/\/ Handle contact update\r\n }\r\n case 'DELETE_CONTACT':\r\n return {\r\n \/\/ Handle contact delete\r\n }\r\n case 'EMPTY_CONTACT_LIST':\r\n return {\r\n \/\/ Handle contact list\r\n }\r\n default:\r\n return state\r\n }\r\n}<\/code><\/pre>\n
default<\/code> for when the value of
action.type<\/code> specified in the action object does not match what we have in the reducer \u2014 say, if for some unknown reason, the action looks like this:<\/p>\n
const action = {\r\n type: 'UPDATE_USER_AGE',\r\n payload: {\r\n age: 19\r\n }\r\n}<\/code><\/pre>\n
Putting everything together<\/h3>\n
\n reducer example<\/a> by Kingsley Silas Chijioke (@kinsomicrote<\/a>)
\n on CodePen<\/a>.<\/span>\n<\/p>\n