1. 19
    Using createAsyncThunk and the builder API to Generate Redux Actions for an API call
    2m 13s

Using createAsyncThunk and the builder API to Generate Redux Actions for an API call

Jamund Ferguson
InstructorJamund Ferguson
Share this video with your friends

Social Share Links

Send Tweet

The key reason to use createAsyncThunk is that it generates actions for each of the different outcomes for any promised-based async call: pending, fulfilled, and rejected. We then have to use the builder callback API on the extraReducers property to map these actions back into reducer methods we then use to update our state. It's a bit of of a process but it's simpler than the alternative, which is to create a bunch of actions by hand and manually dispatch them.


  • createAsyncThunk takes a type argument (which I referred to as a label) and a function called a payloadCreator which is basically just an async function (or function returning a promise) that goes and collects data.

  • The builder API is one way to define extraReducers (you can also pass in an object with a string). It's semantically similar to a switch statement and includes methods like addCase and addDefaultCase.

Jamund Ferguson: [0:00] In cartSlice.ts, import { createAsyncThunk } from "@reduxjs/toolkit". Below that, import { checkout, CartItems } from "../../app/api". You'll see that this checkout conflicts with the one we have down at the bottom of the screen. I'm just going to go ahead and delete our checkoutThunk for now.

[0:18] Just above createSlice, let's add export const checkoutCart = createAsyncThunk(). Pass in for the action type "cart/checkout". The second argument is going to be an async function which takes as its first argument items of type CartItems. Inside the function, type const response = await checkout(items), and then, return response.

[0:44] Down at the bottom of the file, in our extraReducers section, let's replace our builder cases from these hard-coded strings to checkoutCart.pending and checkoutCart.fulfilled. CreateAsyncThunk generates these actions for us.

[1:00] In addition to the pending and fulfilled states, createAsyncThunk also adds support for the rejected state. Here, we'll say state.checkoutState = "ERROR". This will be called anytime that the promise we send to createAsyncThunk gets rejected.

[1:16] Open up Cart.tsx. Instead of importing checkout, let's import checkoutCart from "./cartSlice". Then, scroll down into onCheckout, we'll replace checkout with checkoutCart(items). Remember, we've already pulled in items with useAppSelector from before. Now, we're dispatching a thunk that will make the API call.

[1:35] If we go back to our app, we have some logic in our Checkout API that returns an error any time we try to check out without any items. You can see that working here. If we do have items in the cart and we go to Checkout, you see loading state lasts for about half a second, and then the cart resumes its ready state.

[1:50] Just to recap what we did, we use createAsyncThunk to generate an action creator which we named checkoutCart that dispatches actions based on the response of our Checkout API call.

[2:00] Those three actions, pending, fulfilled, and rejected, we handle as cases in our extraReducers function. Rather than building these thunk functions by hand, createAsyncThunk generates and dispatches the appropriate actions for us.