UI/UX Design

Error handling in React using Error Boundaries

If you have some experience with React, you probably know already that some errors are really frustrating and difficult to resolve.

For example:
TypeError: Cannot read property '_currentElement' of null
Cannot read property 'name' of undefined

Typical symptoms include stack traces that are going through React internals without even a single line of your own code. A JavaScript error in a part of the UI shouldn’t break the whole app.
To solve this problem, in React 16 there is a new concept of an “error boundary”.

What are error boundaries?

Error boundaries are React components available since React 16 that are used to catch JavaScript errors anywhere in their child component tree, log those errors, and display a fallback UI instead of the component tree that crashed. Error boundaries catch errors during rendering, in lifecycle methods, and in constructors of the whole tree below them.

Please note that in situations when there are errors thrown inside of a render call or lifecycle methods which are causing confusing errors and were not caught by any error boundary, React will unmount the entire component tree.

How to use?

A class component becomes an error boundary if it defines a new lifecycle method called componentDidCatch(error, info). This will be called with any uncaught error that bubbles up from the component’s children’s lifecycle methods, constructors, or render methods (but not the component’s own errors).

 
  
  

class ErrorBoundary extends React.Component {
  constructor(props) {
    super(props);
    this.state = { hasError: false };
  }

  componentDidCatch(error, info) {
    this.setState({ hasError: true });
  }

  render() {
    if (this.state.hasError) {
      return <h1>Something went wrong.</h1>;
    }
    return this.props.children;
  }
}

  

 
Now you can use it as a regular component:

  
  

<ErrorBoundary>
  <CustomComponent />
</ErrorBoundary>

  

As you can see, by using error boundaries you can isolate sections of your app’s component tree from each others’ errors so users can still use the working sections of your app. If this blog would use React and the comment section would fail to load, you should still be able to read the article instead of seeing an error.

How does it work?

The componentDidCatch() method works like a JavaScript try{ }catch(e){ } block, but for components. Only class components can be error boundaries. In practice, most of the time you’ll want to declare an error boundary component once and use it throughout your application.

Error boundaries exist because using try{ }catch(e){ } doesn’t work with the JSX rendering model.

  
  

<div>
  {
    try {
      <CustomComponent/>
    } catch(error) {
    errorHandler(error)
      }
  }
</div>

  

Error boundaries will only catch errors in the components below them in the tree. An error boundary can’t catch an error within itself. If an error boundary fails trying to render the error message, the error will propagate to the closest error boundary above it.

Andy

UI/UX Designer & Front-end Engineer based in Dublin currently working @IBM.
I write about: UI/UX Design, Javascript, HTML, CSS, React JS and React Native

Add comment