Handle HTTP Errors with React

Share this video with your friends

Send Tweet

Unfortunately, sometimes a server request fails and we need to display a helpful error message to the user. In this lesson we’ll handle a promise rejection so we can collect that error information, and we’ll also learn how we can best display manage the state of our request so we have a deterministic render method to ensure we always show the user the proper information based on the current state of our React component.

A common mistake people make is to create a state variable called isLoading and set that to true or false. Instead, we’ll be using a status variable which can be set to idle, pending, resolved, or rejected. You can learn more about why this is important from Stop using isLoading booleans.

Stephen James
Stephen James
~ 4 years ago

I notice that you didn't use .catch for you promise in useEffect. Is this a style you prefer? Is there an advantage?

Kent C. Dodds
Kent C. Dodds(instructor)
~ 4 years ago

Yes, there is an advantage:

promise.then(
  () => {
    throw new Error('oh no')
  },
  () => { /* not called */ }
).catch(() => { /* called because the success handler failed */ })

In my example, I only want to catch errors with the promise itself, not with the success handler.

Quang Le
Quang Le
~ 4 years ago

It is very nice that you show how to make an async request and handle errors from a React component. In my opinion, this kind of pattern is commonly used to interact with remote server and I wonder if there is any built-in component or third party component library to simplify this process? Thank you.

Kent C. Dodds
Kent C. Dodds(instructor)
~ 4 years ago

Take a look at react-query

Dimitar Danailov
Dimitar Danailov
~ 4 years ago

@kent the course is really good and useful.

I want to share my comment how the source code can be better. The source code implementation is:

const [status, setStatus] = React.useState('idle')

The native React hook can be replaced with state machine: https://xstate.js.org/viz/

Kyle Shevlin has a great course: Introduction to State Machines Using XState

The state machine can be:

const fetchMachine = Machine({
    id: 'fetch',
    initial: 'idle',
    context: {
      retries: 0
    },
    states: {
      idle: {
        on: {
          FETCH: 'loading'
        }
      },
      loading: {
        on: {
          RESOLVE: 'success',
          REJECT: 'failure'
        }
      },
      success: {
        type: 'final'
      },
      failure: {
        on: {
          RETRY: {
            target: 'loading',
            actions: assign({
              retries: (context, event) => context.retries + 1
            })
          }
        }
      }
    }
  })
Dmitry
Dmitry
~ 3 years ago

Yes, I think it is worth mentioning that this approach of handling the request status - is the state machine and basically every network request should be done using such an approach.

Ian Poston
Ian Poston
~ 8 months ago

the new endpoint doesn't send an error status. update code to handle a null data.

if (status === 'rejected' || pokemon === null) { return 'Oh no...' }