Async Error Handling Logic in Thunks

Handling errors in a Redux toolkit application using thunks.

We'll cover the following

Introduction

As you’ll come to see, handling errors in thunks is just as straightforward as the loading state handled in the last lesson.

Let’s get right into it. But first, here’s the flow we’re gunning for within the fetchTweets thunk:

  • Wrap API call in a try-catch block.
  • Catch errors if they occur and dispatch a new action.
  • Save error message.
  • Handle error state in the application UI.
// before 
export const fetchTweets = (searchValue, numberOfResults) => async (
  dispatch
) => {
  dispatch(isLoadingTweets());
  const tweets = await findTweets(searchValue, numberOfResults);
  dispatch(loadingTweetsSuccess(tweets));
};


// now 
export const fetchTweets = (searchValue, numberOfResults) => async (
  dispatch
) => {
  // wrap in a try catch 
  try {
    dispatch(isLoadingTweets());
    const tweets = await findTweets(searchValue, numberOfResults);
    dispatch(loadingTweetsSuccess(tweets));
  } catch (error) {
    // to be described
  }
};

We’re going to dispatch a loadingTweetsFailed action if there’s an error. Let’s go ahead and create an associating reducer in the slice object.

const finderSlice = createSlice({
  name: "finder",
  initialState,
  reducers: {
    // ... 
    // see this 👇
    loadingTweetsFailed(state, payload) {
      state.isLoading = false;
      state.error = payload;
    },
  },
});

// add loadingTweetsFailed to the exported action creators 
export const {
  isLoadingTweets,
  loadingTweetsSuccess,
  loadingTweetsFailed, // 👈 see this 
} = finderSlice.actions;

This is awesome. loadingTweetsFailed may now be invoked with a payload. We’ll have this payload be whatever the error message is:

export const fetchTweets = (searchValue, numberOfResults) => async (
  dispatch
) => {
  try {
    dispatch(isLoadingTweets());
    const tweets = await findTweets(searchValue, numberOfResults);
    dispatch(loadingTweetsSuccess(tweets));
  } catch (error) {
    // see this 👇
    // grab error message and dispatch action 
    const errorMsg = error.toString();
    dispatch(loadingTweetsFailed(errorMsg));
  }
};

With this action dispatched now, we can handle the error state within the UI. This all happens in Finder.js.

First, let’s grab the error state:

// Finder.js
export function Finder() {
  // ...
  // deconstruct 'error'
  const { tweets, isLoading, error } = useSelector((state) => state.finder);
}

Then, render some UI based on that:

import {
  // ...,
  Alert,
  AlertIcon,
  AlertDescription,
  AlertTitle,
  CloseButton,
} from "@chakra-ui/react";

export function Finder() {
  // ...
  
  if (error) {
    return (
      <Alert status="error">
        <AlertIcon />
        <AlertTitle mr={2}>An Error occurred!</AlertTitle>
        <AlertDescription>
          We couldn't fetch tweets right now. Please try again later.
        </AlertDescription>
        <CloseButton position="absolute" right="8px" top="8px" />
      </Alert>
    );
  }

}

And now we should have the following UI whenever an error is triggered from fetching the tweets:

Get hands-on with 1200+ tech skills courses.