Blog>
Snippets

Using createAsyncThunk with Redux Toolkit 2.0 for API Calls

Explain how to use the createAsyncThunk API with Redux Toolkit 2.0 to handle asynchronous operations like API calls, including loading states and error handling.
// 1) Define the async thunk using createAsyncThunk
import { createAsyncThunk } from '@reduxjs/toolkit';

export const fetchUserById = createAsyncThunk(
  'users/fetchByIdStatus',
  async (userId, thunkAPI) => {
    try {
      const response = await fetch(`https://reqres.in/api/users/${userId}`);
      let data = await response.json();
      return data.data;
    } catch (error) {
      return thunkAPI.rejectWithValue({ error: error.message });
    }
  }
);
Defines an async thunk for fetching user data by ID using Redux Toolkit's createAsyncThunk function. It handles the asynchronous API call and the possible error that might occur, and it prepares it to be dispatched in a Redux store.
// 2) Use the async thunk in a slice
import { createSlice } from '@reduxjs/toolkit';

const userSlice = createSlice({
  name: 'user',
  initialState: {
    entities: [],
    loading: 'idle',
    error: null
  },
  reducers: {},
  extraReducers: (builder) => {
    builder
      .addCase(fetchUserById.pending, (state) => {
        state.loading = 'pending';
      })
      .addCase(fetchUserById.fulfilled, (state, action) => {
        state.entities.push(action.payload);
        state.loading = 'idle';
      })
      .addCase(fetchUserById.rejected, (state, action) => {
        state.loading = 'idle';
        state.error = action.payload?.error || 'Something went wrong';
      });
  }
});

export default userSlice.reducer;
Creates a user slice with a loading state and error handling using createSlice. The slice uses the previously defined async thunk and updates the state accordingly based on the action type (pending, fulfilled, or rejected) dispatched by the thunk.
// 3) Dispatch the async thunk from a React component
import React from 'react';
import { useDispatch } from 'react-redux';
import { fetchUserById } from './userSlice';

const UserComponent = () => {
  const dispatch = useDispatch();

  React.useEffect(() => {
    dispatch(fetchUserById(1));
  }, [dispatch]);

  // Rendering UI based on loading and error states can go here
  // ...

  return <div>User Component</div>;
};

export default UserComponent;
This is a React functional component that dispatches our async thunk when the component mounts. It uses useEffect to dispatch the fetchUserById action with a user ID of 1 as soon as the component renders.
/* 4) (Optional) Redux store setup example */
import { configureStore } from '@reduxjs/toolkit';
import userReducer from './userSlice';

const store = configureStore({
  reducer: {
    user: userReducer
  }
});

export default store;
This is an optional code sample showing how to set up a Redux store using configureStore from Redux Toolkit. It registers the userSlice reducer under the key 'user'.