Before createAPI came out, my current team needed a way of cleaning up all of the loading logic around our async thunks. We were using @reduxjs/toolkit
, with createSlice
and createAsyncThunk
. A simple solution to our problem was essentially adding a match on the extraReducer builder for any thunk that included “:load” in its name, and then setting the appropriate loading state for the thunk in there.
createSlice({
...options,
extraReducers: (builder) => {
builder
.addMatcher(
(action: AnyAction) =>
action.type.includes("/pending") &&
action.type.includes(options.name) &&
action.type.includes(":load"),
(state) => {
state.state = StateStatus.PENDING;
}
)
.addMatcher(
(action: AnyAction) =>
action.type.includes("/fulfilled") &&
action.type.includes(options.name) &&
action.type.includes(":load"),
(state) => {
state.state = StateStatus.FULFILLED;
}
)
.addMatcher(
(action: AnyAction) =>
action.type.includes("/rejected") &&
action.type.includes(options.name) &&
action.type.includes(":load"),
(state) => {
state.state = StateStatus.REJECTED;
}
);
},
});
Now, after adding this to our slice, we can do something akin to this when creating API thunks:
const fetchUserById = createAsyncThunk(
'users/fetchByIdStatus:load',
async (userId, thunkAPI) => {
const response = await userAPI.fetchById(userId)
return response.data
}
)
The :load
part of the thunk name will match with our extra reducers and automatically update the lifecycle state of the request.
But then doing this to every slice is a bit tedious. So I’ve created a package that essentially does this for you. You don’t have to write any of the setup, just replace createSlice
with createAPISlice
from @ryfylke-react/create-api-slice
and you’re good to go. Make sure that your async thunks that need to affect the slice’s loading state have :load
appended to them (you can change this key in the options object).
You can read more about create-api-slice
on the Github repository.