Refactoring Tweetfind to Use createAsyncThunk

Learn to use the createAsyncThunk utility function in a practical way.

We'll cover the following

Practical createAsyncThunk

We’ve talked a lot about createAsyncThunk, but talk is cheap.

Update the manually created thunk to use createAsyncThunk:

// finderSlice.js
// before 
export const fetchTweets = (searchValue, numberOfResults) => async (
  dispatch
) => {
  try {
    dispatch(isLoadingTweets());
    const tweets = await findTweets(searchValue, numberOfResults);
    dispatch(loadingTweetsSuccess(tweets));
  } catch (error) {
    const errorMsg = error.toString();
    dispatch(loadingTweetsFailed(errorMsg));
  }
};

// now 
import { createAsyncThunk } from "@reduxjs/toolkit";

const FETCH_TWEETS = "FETCH_TWEETS";
export const fetchTweets = createAsyncThunk(
  FETCH_TWEETS,
  // 👇 note params
  async (params, thunkAPI) =>
    await findTweets(params.searchValue, params.numberOfResults)
);

See how succinct the createAsyncThunk version is?

Now, we need to update the createSlice case reducers.

// finderSlice.js 
// before 
const finderSlice = createSlice({
  name: "finder",
  initialState,
  reducers: {
    loadingTweetsSuccess(state, { payload }) {
      state.tweets = payload;
      state.isLoading = false;
      state.error = null;
    },
    isLoadingTweets(state) {
      state.isLoading = true;
    },
    loadingTweetsFailed(state, payload) {
      state.isLoading = false;
      state.error = payload;
    },
  },
});

// now 
const finderSlice = createSlice({
  name: "finder",
  initialState,
  // 👇 use extraReducers NOT reducers 
  extraReducers: {
    [fetchTweets.fulfilled]: (state, { payload }) => {
      state.tweets = payload;
      state.isLoading = false;
      state.error = null;
    },
    [fetchTweets.pending]: (state) => {
      state.isLoading = true;
      state.error = null;
    },
    [fetchTweets.rejected]: (state, { payload }) => {
      state.isLoading = false;
      state.error = "We couldn't fetch tweets right now. Please try again later.";
    },
  },
});

Finally, the argument passed to the thunk is now an object. We need to update the argument passed when the thunk is dispatched in Finder.js:

// before 
dispatch(fetchTweets(searchValue, numberOfResults));
// now 
dispatch(fetchTweets({ searchValue, numberOfResults }));

And with that, the application should work as expected!

While you can certainly create your thunk manually, createAsyncThunk performs the heavy lifting for you. It’s the recommended approach for handling async request lifecycles with redux-toolkit.

Get hands-on with 1200+ tech skills courses.