What is createAsyncThunk in Redux-Toolkit

31 May, 2021 - 5 min read

Redux toolkit is an opinionated, batteries-included toolset for efficient Redux development. I tried redux before and I didn’t like it, you can easily get lost. But the redux toolkit is easy and fast.

What is redux toolkit

It is an opinionated, batteries-included toolset for efficient Redux development. Here are the four features of redux toolkit.

  • Simple - Redux toolkit comes with utilities to simplify common use cases such as store, reducers, and immutable logic.
  • Opinionated - It comes with default ways to setup your store, and it includes commonly used redux addons builtin.
  • Powerful - You can write mutative immutable update logic and create entire slices of state automatically.
  • Effective - Redux toolkit lets you focus on the logic part of your app.

Core redux has some complications that redux toolkit seeks to solve. Redux has the following concerns:

  • Store configuration was too complicated
  • Many packages has to added to do anything meaningful with redux
  • Redux needs too much boilerplate code

This post assumes you already know about redux toolkit and are only interested in createAsyncThunk. So what is createAsyncThunk?.

What createAsyncThunk

createAsyncThunk is a function that accepts an action type and a function that returns a promise, it also generates a thunk that dispatches pending, fulfilled and rejected types based on the promise.

Example

Assume you have a jobs REST api that you want to fetch with your redux toolkit. You could right reducers for startLoading, loadJobs, and loadingJobsError in your createSlice function as follows.

export const jobsSlice = createSlice({ name: "jobs", initialState: { jobsLoading: false, jobs: [], failedMessage: "", }, reducers: { startJobsLoading: (state) => { state.jobsLoading = true; }, loadJobs: (state, action) => { state.jobs = action.payload; state.jobsLoading = false; }, loadingJobsError: (state, action) => { state.jobsLoading = false; state.failedMessage: action.payload }, }, }); export const { startJobsLoading, loadingJobsError, loadJobs } = jobsSlice.actions;

Simplifying with createAsyncThunk

If you want to simplify this code, you can use createAsyncThunk function to take care of all those reducers. Here is how you can rewrite the above code using the createAsyncThunk.

import { createAsyncThunk, createSlice } from "@reduxjs/toolkit"; import { axios } from "axios"; // First, create the thunk const getJobs = createAsyncThunk( "jobs/getJobs", async (thunkAPI) => { const res = axios.get("https://remoteok.io/api"); return res.data; } ); const getJob = createAsyncThunk( "jobs/getJobs", async (id, thunkAPI) => { const res = axios.get(`https://remoteok.io/api/${id}`); return res.data; } ); // Then, handle actions in your reducers: const jobsSlice = createSlice({ name: "jobs", initialState: { jobsLoading: false, jobs: [], failedMessage: "", }, reducers: {}, extraReducers: { [getJobs.pending]: (state, action) => { state.jobsLoading = true; }, [getJobs.fulfilled]: (state, action) => { state.jobs.push(action.payload); state.jobsLoading = false; }, [getJobs.rejected]: (state, action) => { state.jobsLoading = false; state.failedMessage: action.payload }, [ [getJob.fulfilled]: (action) => return action.payload }, });

createAsyncThunk anatomy

Note Reducers from the createAsyncThunk are called in the extraReducers field, and NOT reducers. createAsyncThunk accepts three parameters:

  • String action type value "jobs/getJobs"
  • The paload creator callback function,
  • And the options object

type

It's a string used to index additional action types such as pending, fulfilled and rejected, the additional action types represents the lifecycle of the async callback function.

In the above example. we used jobs/getJobs type string, and it will generate the following redux action types:

  • pending: jobs/getJobs/pending
  • fulfilled: jobs/getJobs/fulfilled
  • rejected: jobs/getJobs/rejected

payLoad creator async function

This function returns a promise with the result of async login e.g an axios or fetch function. If this function encounters an error in it's lifecycle, it return reject promise Error instance, or descriptive error message.

payLoadcreator function anatomy

The payload creator function can be called with two arguments:

  • arg: a string or object value, for example if you want to request for individual job posting, you have to pass the id or slug of that particular job in your dispatch. For example in our getJob function, we passed the id argument.

    Note The arguments can only be a single string, int or object value.

  • thunkAPI: this is an object that contains all the Redux thunk function parameters. It also contains:

    • dispatch
    • getState
    • extra - Extra arguments for the thunk middleware on setup
    • requestId - auto generated unique string ID value that identifies the request sequence.
    • signal - This is a signal object used to identify if another part of the app is requesting a cancellation. It is an AbortCOntroller.signal object
    • rejectWithValue(value, [meta]) - a function you can return in your action creator to return a reject responce with defined payload and meta.
    • fulfillWithValue(value, meta) - a function that can be returned in your action creator to fulfil with a value while having the ability of adding to fulfilledAction.meta.

Options object

This is an object with these optional fields:

  • condition(arg, {getState, extra}): boolean: It is a callback function you can use to skip execution of the payload creator and all action dispatches.
  • dispatchConditionRejection: if condition() returns false, by default actions will not be dispatched. Set this to true if you want to dispatch a rejected action.
  • dGenerator(): string - Used to generate a requestId for the request sequence.
  • serializeError(error: unknown) => any: This can override the miniSerializeError to define custom serialization logic.
  • getPendingMeta({ arg, requestId }, { getState, extra }): any:: This creates an object that will be merged with pendingAction.meta.

What createAsyncThunk returns

The thunk action creator function will have plain action creators for the pending, fulfilled, and rejected cases attached as nested fields. On the getJobs example above, createAsyncThunk will generate the following functions

  • getJobs.pending: an action creator that dispatches an 'jobs/getJobs/pending' action
  • getJobs.fulfilled: an action creator that dispatches an 'jobs/getJobs/fulfilled' action
  • getJobs.rejected: an action creator that dispatches an 'jobs/getJobs/rejected' action
Theophilus Ngaribvume

Hi 👋, i'm Theo Nga, a software developer based in Zimbabwe, Harare. I love JavaScript and Python.

© 2021, Theo Nga. All Rights Reserved.