Understanding Error Boundaries in React

Lotanna Nwose
Bits and Pieces
Published in
7 min readFeb 20, 2019

--

Photo by Nathan Dumlao on Unsplash

Tip: Share and reuse React Components

Use Bit to encapsulate React components with all their dependencies and setup. Share them in Bit’s cloud, collaborate with your team and use them anywhere.

Shared React components in Bit’s cloud

Error Handling in JavaScript

In JavaScript we handle most errors during execution of code with a try catch. A try block is the block of code in which exceptions occur. A catch block catches and handles try block exceptions.

This could look like the code block below:

Where we can wrap a process that might return an error or exception in a try block and then offer a kind failsafe with the catch block after it has executed.

Error Handling in React

With React we would expect to handle the error with similar syntax, something like this:

This code block above would not work because the way React works with the virtual DOM, it waits for changes to be finished before updating it in the real DOM. To achieve this efficiently, React caches component changes in a kind of asynchronous process behind the scenes that would make the block return promises. Later in this article we would see how React handles errors…

Errors in React

So before React 16 came, you must have experienced a moment of really confusing and cryptic error messages while using React like this example snippet below:

Here we see no really meaningful information on what exactly went wrong. This mostly drives developers to visit Github Gists and StackOverflow to spend hours trying to see if anyone’s error message matches their own error message and luckily find a solution.

Most times, the error had occurred somewhere inside a component in your application and React did not handle it (gracefully) on next render. This could be due to the caching strategy of having to push from virtual to actual DOM so, the entire application crashes down. In React 16 however, a kind of try-catch for components is introduced as Error Boundaries to take care of this problem allowing you catch these errors before they get to the internals of the React application.

Introducing Error Boundaries

The premise upon which the Error Boundaries idea in React was born from is that JavaScript errors in the user interface should not be allowed to break the whole application.

Error boundaries are React components that catch JavaScript errors anywhere in their child component tree, and does something worthwhile with it like displaying a fallback interface instead of the component tree that crashed or logging the exact error. Error boundaries catch errors during rendering, in lifecycle methods, and in constructors of the whole tree below them, unmount the component tree while maintaining the usual workings and renderings of the rest of the React application.

Error Boundaries in React

An Error Boundary in React is therefore defined as a Class Component that defines one or both of static getDerivedStateFromError() or componentDidCatch()lifecycle methods. The first one, static getDerivedStateFromError() is used to render a fallback user interface after an error has been thrown and the second one, componentDidCatch() is used to log error information to an error tracking service say Sentry. This is the official syntax below:

Then you can use it as a regular component like thus:

<ErrorBoundary>
<MyWidget />
</ErrorBoundary>

Demo

Let us see the importance of the Error Boundary with a small demonstration.

  • Create a new React Application
  • OR download an already created application here
  • Use a terminal to navigate to the application folder and run this:
npm install
  • Go to the src folder and create a new Artists component (Artists.js)
  • Copy the functional component code below to the Artists.js component you just created:

this is a simple functional component that throws an error on certain pre-defined conditions.

  • Go to your App.js file and copy the code below for the interface:
  • run the application on the dev server
npm start

this would display a list of artists performing at the Grammy’s tonight.

If we go ahead and fulfil the condition set in the functional component for throwing the errors in just one Artist element, we see the entire React application crash.

  • Change one of the artists element to peruzzi like so:
<Artists artistName=’peruzzi’> </Artists>

You would agree with me that it would be nicer to have just that particular element fail, letting the rest of the application to continue running. This is exactly why the Error Boundary was introduced. So that if a component throws an error, its output gets handled by the Error Boundary and the rest of the application continues unaffected.

Static getDerivedStateFromError

This is the first lifecycle method React provides for handling Error Boundaries. It receives the error as a parameter and returns the new error state object in the body. This state property can now be used in the render to create a failsafe interface. Your component would need to have an initially set state.

With our sample demo above, this s how we create an Error Boundary:

  • In the src folder of your application create an ErrorBoundary.js file.
  • Copy the code below

the this.props.children is pointing to the component we are actually rendering in the where errors do not exist.

  • Wrap the intended component in the App.js with the ErrorBoundary.
  • Run the app on your development server
npm start

You will see the same error message as before and this is expected because the team at React designed Error Boundaries in a way that would not discourage the clear error logging features developers enjoy in the development environment.

Error Boundaries were designed by default in the development environment not to show fallback interface on purpose.

If you built out your React application in production, you would see the fallback interface. There is however a workaround I found in chrome browsers (I do not know yet if it works on other browsers). Just click the close button at the right of the error message to reveal the unbroken application like it would in production environment.

This would show the application unbroken with the error boundary fallback like this:

We can also wrap the individual elements with the Error Boundary Instead so that other elements can render alongside the preset fallback interface.

The Application would then look like this:

Here we can see the very essence of the Error Boundary at work. You can access the code to the Demo here.

Where to Use Error Boundaries

This has been left to the developers discretion, you can decide to wrap top-level route components in fallback interfaces just the way server-side frameworks handle crashes. You can wrap entire components or nested children components or bits of them, it should basically depend on the user experience you are aiming to provide.

A typical example can be in our Demo, we see that it makes sense to display other artists regardless of the error affecting just one artist. It would therefore not be wise to wrap the Error Boundary around the components as a whole. Wrapping individual elements with the Error Boundary is a better call here.

⚠️ Caution Tips

Error boundaries do not catch errors for:

  • Event handlers.
  • setTimeout or requestAnimationFramecallbacks.
  • Server side rendering.
  • Errors thrown in the error boundary itself, rather than in its children.

Conclusion

It is very crucial to note that as of React 16, errors that were not caught by any error boundary will result in un-mounting of the whole React component tree. Error Boundaries are such a React blessing and the freedom of use that it affords is amazing. I want to know how you are using them down in the comments, happy coding!

--

--

Helping Startups with Webhooks management at Convoy so they can focus on their core product offerings. Twitter:@viclotana