Additional Reducers in Redux
Let's open our product app, and in it the file productsSlice.js. You may have noticed that we created the thunk fetchProducts as a separate function? We did this because createSlice does not support defining thunks. How can we then make the products slice reducer respond to actions that are defined outside of products? After all, we need to process the actions that the thunk fetchProducts sends.
For such cases, createSlice has a extraReducers property, which allows you to add additional reducers, which in turn will handle actions defined not in this slice.
Let's now add another method extraReducers in the body of the createSlice function after the reducers property with all the reducers:
extraReducers() {},
We need to pass this method a builder object, which has methods that can be used to add additional reducers:
extraReducers(builder) {},
We will use one of the builder methods - addCase, which takes the action creator as the first parameter and the reducer as the second. One of the actions that fetchProducts will send to us when making a request is fetchProducts.pending, which tells us that the request has been sent. In this case, let's change the status to 'in progress' (before it was 'idle'):
extraReducers(builder) {
builder.addCase(fetchProducts.pending, (state) => {
state.status = 'in progress'
})
},
Now let's handle the action that will be sent in case of a successful request. Here we will not only change the status in the state to 'success', but also take the products into the slice products from the payload action. To collect all the products we will need the concat method:
extraReducers(builder) {
builder
.addCase(fetchProducts.pending, (state) => {
state.status = 'in progress'
})
.addCase(fetchProducts.fulfilled, (state, action) => {
state.status = 'success'
state.products = state.products.concat(action.payload)
})
},
In case of an unsuccessful request, we change the status to 'fail' and write an error message to the state:
.addCase(fetchProducts.rejected, (state, action) => {
state.status = 'fail'
state.error = action.error.message
})
If we now launch our application and click on 'Products' in the menu, then after a couple of seconds (remember the delay we set on the server?) we will see a list of products.
We will also see changes in Redux DevTools. Now our products will appear in the state (check the 'State' tab) if you click on the products/fetchProducts/fulfilled action. A new status 'success' will also appear there. Now click on the products/fetchProducts/pending action and see how the 'State' tab is different now.
The only unpleasant moment that can happen to you (I talked about this in the previous lesson) is duplicating the data request. As a result, we will have not 8, but as many as 16 products in the list and critical warnings in the developer console. Let's deal with this in the next lesson.
Open your students app. Open the studentsSlice.js file in it. In the body of the createSlice function, after the reducers property, add the extraReducers property. Pass the extraReducers method builder.
Using the builder.addCase method, add handling for the pending, fulfilled, and rejected actions that fetchStudents dispatches when requesting data, as shown in the tutorial.