Blog>
Snippets

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(
  'user/fetchUserData',
  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">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Redux Toolkit Migration</title>
</head>
<body>
  <div id="app"></div>
  <script src="path_to_your_bundled_javascript_file.js"></script>
</body>
</html>
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.