Introduction to thunks in Redux
In the previous chapter, we set up a server, database, and client to communicate. Now we need to build the final bridge that will help our 'synchronous'
Redux-based application interact with the asynchronous client we created in the last lesson of the previous chapter to send requests and receive the necessary data in response.
As we remember from the first lessons of the previous section, Redux knows nothing about working with asynchronous logic, and for this we will use thunk middleware. This middleware allows us to work with dispatched actions, use the dispatch
and getState
store methods in our thunk code, and also help the dispatch
method work not only with regular JS objects, but also with entities such as functions and promises.
Typically, a thunk function is called with two arguments, dispatch
and getState
(if needed), which can be used in the body of the function. It can be used to dispatch regular actions. It can also be dispatched via store.dispatch
. An example of such a function is shown below:
const changeColorThunk = (dispatch, getState) => {
const colorBefore = getState()
console.log(`Old Color: ${colorBefore.color}`)
dispatch(changeColor())
const colorAfter = getState()
console.log(`New Color: ${colorAfter.color}`)
}
store.dispatch(changeColorThunk)
Let's now open our product app. The first thing we should get from the server when we launch the app is a list of products. Since thunks are usually written in slice files, we'll open the productsSlice.js
file.
The good news is that we don't have to bother with setting up Redux Thunk, as RTK's configureStore
function will already do that for us. So let's just add createAsyncThunk
to the imports in the file:
import { createSlice, nanoid, createAsyncThunk } from '@reduxjs/toolkit'
Let's also add our client to the import:
import { client } from '../../api/client'
Now, using createAsyncThunk
, we'll create our first thunk for receiving products, we'll do this right after declaring the initialState
object:
export const fetchProducts = createAsyncThunk()
The first parameter of createAsyncThunk
will take a string for the type of action to generate, and the second one will be a callback function for payload
, which will return either the data or a promise with an error (see client.js
file). In the function code, we call client.get
and pass it the path we specified on the server (see the accepted parameters of http.get
in server.js
):
export const fetchProducts = createAsyncThunk(
'products/fetchProducts',
async () => {
const response = await client.get('/fakeServer/products')
return response.data
}
)
Open your students app. Open the studentsSlice.js
file in it. Import the createAsyncThunk
function to create the thunk, and the client
function to send API requests to the server.
Immediately after declaring the initialState
object, use createAsyncThunk
to create a fetchStudents
thunk to get the list of students, which will send a GET request to /fakeServer/students
specified in your server.js
file and return response.data
as shown in the tutorial materials. As the first parameter to createAsyncThunk
, specify the string students/fetchStudents
for the action type.