Loading state with Redux toolkit

Articles|HÃ¥kon Underbakke | almost 2 years ago

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.