Migrating from Redux Thunk to Redux Toolkit

Demonstrate the process of migrating a pre-existing Redux thunk middleware to the Redux Toolkit's createAsyncThunk for better Redux v5.0.0 compatibility.
// Old Redux Thunk action creator
export const fetchUserData = (userId) => {
  return (dispatch) => {
    dispatch({ type: 'USER_FETCH_REQUESTED' });
    return fetch(`/api/users/${userId}`)
      .then(response => response.json())
      .then(data => dispatch({ type: 'USER_FETCH_SUCCEEDED', payload: data }))
      .catch(error => dispatch({ type: 'USER_FETCH_FAILED', payload: error }));
This is an example of a traditional Redux thunk action creator. It dispatches actions based on asynchronous API call results.
// Slice.js using Redux Toolkit's createSlice and createAsyncThunk
import { createSlice, createAsyncThunk } from '@reduxjs/toolkit';

// New Redux Toolkit createAsyncThunk
export const fetchUserData = createAsyncThunk(
  async (userId, thunkAPI) => {
    const response = await fetch(`/api/users/${userId}`);
    if (!response.ok) {
      return thunkAPI.rejectWithValue(await response.json());
    const data = await response.json();
    return data;

// Slice to handle the action
export const userSlice = createSlice({
  name: 'user',
  initialState: {},
  reducers: {},
  extraReducers: {
    [fetchUserData.pending]: (state) => {
      // Handle pending state
    [fetchUserData.fulfilled]: (state, action) => {
      // Handle fulfilled state and update the state with payload
    [fetchUserData.rejected]: (state, action) => {
      // Handle rejected state
This code snippet replaces the traditional Redux thunk action creator with Redux Toolkit's createAsyncThunk, which automatically handles dispatching actions for pending, fulfilled, and rejected states of the async operation. A slice is also defined to handle the action states using createSlice.
// store.js setup for Redux Toolkit
import { configureStore } from '@reduxjs/toolkit';
import { userSlice } from './userSlice';

// Configure the store with Redux Toolkit, automatically setting up the middleware
export const store = configureStore({
  reducer: {
    user: userSlice.reducer,
This is the new Redux store configuration using Redux Toolkit's configureStore. It sets up the middleware automatically and includes the user slice.reducer for the user's state.
<!-- index.html, simple setup for Redux with Redux Toolkit -->
<!DOCTYPE html>
<html lang="en">
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Redux Toolkit Migration</title>
  <div id="app"></div>
  <script src="path_to_your_bundled_javascript_file.js"></script>
This is a simple HTML to setup the Redux application. Your bundled JavaScript file should be included at the end of the body tag.
/* styles.css, basic styling example for the Redux application, */

#app {
  display: flex;
  justify-content: center;
  align-items: center;
  height: 100vh;
A simple CSS snippet to style the #app container element, centering its content both horizontally and vertically.