Catching Asynchronous Errors in React using Error Boundaries

David Barral
Trabe
Published in
2 min readDec 16, 2019
Photo by Thomas Park on Unsplash

React 16.0 introduced Error Boundaries.

Error boundaries are React components that catch JavaScript errors anywhere in their child component tree, log those errors, and display a fallback UI instead of the component tree that crashed.

Take this example:

If we run this code, the ErrorBoundary will catch the error, render the fallback UI (Something went wrong) and log the error to the console.

Error Boundaries are a nice way to centralize error handling in React apps but they can only catch certain errors:

Error Boundaries do not catch errors for:

* Event handlers

* Asynchronous code (e.g. setTimeout or requestAnimationFrame callbacks)

* Server side rendering

* Errors thrown in the error boundary itself (rather than its children)

Most applications fetch data asynchronously, so if our BrokenComponent does that, our ErrorBoundary won’t catch the error and nothing would be rendered. We’ll notice the error because the browser will issue an error in the console (an Uncaught (in promise) on Chrome).

The usual way to fix this is having our component handling its own errors.

But this is such a let down. We cannot use our Error Boundaries to manage all errors in the same fashion, which can lead to duplication.

The problem is that asynchronous code runs outside the render and commit phases of React. How can we fix it then? The solution is right in front of us. Luckily, Dan Abramov is always there to open our eyes:

Dan Abramov on “Throwing Error from hook not caught in error boundary” github issue https://github.com/facebook/react/issues/14981

Just use setState. Throw inside the callback. See how errors are caught by your Error Boundaries.

Let’s extract this snippet to a reusable hook:

And use it in our code:

And that’s it. Now our ErrorBoundary can deal with all errors, both synchronous and asynchronous.

Parting thoughts and a concurrent future

The proposed solution is simple, but to be honest, feels a bit hackish. We are forcing the asynchronous error into the React render phase using a hammer (poor setState). We are not totally comfortable with this, but we haven’t found another option yet. So, if someone has a better solution we are all ears 😃.

Anyway, I sleep more soundly these days after digging into the new React concurrent mode. We will be writing code like the following, which fits this pattern of handling all errors with Error Boundaries:

All this stuff it’s still experimental but it seems that the final version will be very similar (if not the same). It’s good to have our code future proof.

--

--

David Barral
Trabe
Editor for

Co-founder @Trabe. Developer drowning in a sea of pointless code.