React + Redux Toolkit - Fetch Data in Async Action with createAsyncThunk
Tags: react, abotwrotethis
Published: 2023-04-17 17:02:02

If you have worked with React and Redux before, you know that handling asynchronous actions can be a little tricky. Redux Toolkit provides an easy solution to this problem with its `createAsyncThunk` function.

In this blog post, we will cover how to fetch data in an async action using `createAsyncThunk` with React and Redux Toolkit.

## What is Redux Toolkit?

Redux Toolkit is a package created by the Redux team to make working with Redux easier and more efficient. It includes a set of opinionated tools and utilities that make common Redux use cases much simpler, such as store setup, defining reducers, and creating actions.

Here are some of the features that Redux Toolkit provides:

- Provides a simplified way to write Redux logic with less boilerplate
- Includes a `configureStore()` function with sane defaults and good defaults for production code
- Provides utilities to generate action types and action creators
- Includes a powerful `createAsyncThunk` function that makes handling async logic much simpler

## What is createAsyncThunk?

`createAsyncThunk` is a function provided by Redux Toolkit that makes it easy to handle async logic in your Redux actions.

With `createAsyncThunk`, you can define an async action that will automatically dispatch the three Redux actions needed to handle async operations: `pending`, `fulfilled`, and `rejected`.

`createAsyncThunk` also provides some additional options that allow you to customize the behavior of your async action, such as defining how many times it should retry if it fails.

## How to Use createAsyncThunk

Here is an example of how to use `createAsyncThunk` to fetch data from an API:

```javascript
import { createAsyncThunk } from '@reduxjs/toolkit';
import { fetchData } from 'api';

export const fetchUserData = createAsyncThunk(
  'user/fetchUserData',
  async () => {
    const response = await fetchData('/user');
    return response.data;
  }
);
```

In this example, we first import `createAsyncThunk` from `@reduxjs/toolkit`. We also import an API function called `fetchData` that returns a Promise that resolves to the data we want to fetch.

We then define an async action called `fetchUserData` using `createAsyncThunk`. This action will dispatch a `pending` action with the type `user/fetchUserData/pending` when it is first invoked.

It will then call the function passed as the second argument to `createAsyncThunk`, which in this case is an async function that fetches the data from the API. When the Promise returned by this function resolves, it will dispatch a `fulfilled` action with the type `user/fetchUserData/fulfilled` and pass the data as its payload.

If the Promise returned by the function passed to `createAsyncThunk` rejects, it will dispatch a `rejected` action with the type `user/fetchUserData/rejected` and pass the error as its payload.

## How to Use createAsyncThunk with a Loading State

In some cases, you may want to display a loading spinner or message while your async action is pending. To do this, you can create a loading state in your Redux store and update it in the `pending` action handler.

Here is an example of how to do this:

```javascript
import { createSlice } from '@reduxjs/toolkit';
import { fetchUserData } from './actions';

const initialState = {
  data: null,
  isLoading: false,
  error: null
};

const userSlice = createSlice({
  name: 'user',
  initialState,
  reducers: {},
  extraReducers: builder => {
    builder
      .addCase(fetchUserData.pending, state => {
        state.isLoading = true;
      })
      .addCase(fetchUserData.fulfilled, (state, action) => {
        state.isLoading = false;
        state.data = action.payload;
      })
      .addCase(fetchUserData.rejected, (state, action) => {
        state.isLoading = false;
        state.error = action.payload;
      });
  }
});
```

In this example, we define a `isLoading` property in our initial state with a value of `false`. We also define three extra reducers using `builder`, one for each of the three actions dispatched by our `fetchUserData` async action.

In the `pending` action handler, we set `isLoading` to `true`.

In the `fulfilled` action handler, we set `isLoading` back to `false` and update our `data` property with the data returned by the API.

In the `rejected` action handler, we set `isLoading` back to `false` and update our `error` property with the error returned by the API.

## Conclusion

In this blog post, we covered how to use `createAsyncThunk` to fetch data in an async action using React and Redux Toolkit. We also covered how to use a loading state to display a loading spinner or message while our async action is pending.

Redux Toolkit is a powerful tool that can make working with Redux much simpler and more efficient. If you haven't already, I encourage you to give it a try in your next React project.