Tutorial

Error handling in React 16 using Error Boundaries

Draft updated on Invalid Date
Default avatar

By John Kariuki

Error handling in React 16 using Error Boundaries

This tutorial is out of date and no longer maintained.

Introduction

If you have built a React app at any point in your programming career, you probably have experienced an error at some point that was cryptic and did not provide any meaningful context on what actually happened.

This probably means the error occurred at some point in the application and our React component did not handle the error gracefully, well mostly because it was none of its business to make sure the entire app holds.

Introducing Error Boundaries

A JavaScript error in a part of the UI shouldn’t break the whole app. To solve this problem for React users, React 16 introduces a new concept of an “error boundary”.

An Error Boundary is a React component that catches errors within its children and does something meaningful with them such as post them to an error logging service or display a fallback UI for the specific child while maintaining the rest of the React app’s sanity.

Therefore, for a block of functionality to be covered by Error Boundaries, it has to be a child of one in the first place.

Before we get started on an example of how you can use React 16, beware that Error Boundaries will not catch errors in:

  1. Event handlers. ** - Use a try / catch block instead within event handlers. 2. Asynchronous code**
  2. Server-side rendering
  3. Errors within the Error Boundary Component. - You cannot save others if you cannot save yourself first.

componentDidCatch()

Lifecycle methods are special functions that are invoked at different stages in the life of a component. These stages can be categorized into Mounting, Updating, Unmounting and Error handling.

For a component to be considered an Error Boundary, it has to make use of the componentDidCatch() lifecycle method to handle errors. It works in the same way that Javascript’s try/catch works.

the componentDidCatch method is invoked with the error and info parameters that contain more context on the thrown error.

Where To Use Them

Just like the granularity of React component is entirely up to you, Error Boundaries can be as specific as you want them to be. You can have a top-level Error Boundary that prevents the app from crashing due to unexpected occurrences and displaying a more suitable message.

For this article, we will be creating an Error Boundary that only wraps a specific functionality with errors of our own design.

Creating An Error Boundary

To get started, we will create a simple Component that only allows you to enter up to five characters into an input field. Any more than that and we break the internet. Feel free to try out in of the freely available online editors, I personally use CodePen.io.

class FiveMax extends React.Component {
  constructor(props) {
    super(props);
    this.state = { value: ''}
    this.handleChange = this.handleChange.bind(this);
  }

  handleChange(e) {
    this.setState({ value: e.target.value})
  }

  render() {
    if(this.state.value.length > 5) {
      throw new Error('You cannot enter more than five characters!');
    }
    return (
      <div>
        <label>Type away: </label>
        <input type="text" value={this.state.value} onChange={this.handleChange} />
      </div>
    );
  }
}

ReactDOM.render(<FiveMax />, document.getElementById('root'));

If you type in more than five characters, you should get a big shiny error on your console.

You will also notice that your input box disappears due to the error. Perfect! Let’s create an Error Boundary. I’ll call mine Shield.

class Shield extends React.Component {
  constructor(props) {
    super(props);
    // Add some default error states
    this.state = {
      error: false,
      info: null,
    };
  }

  componentDidCatch(error, info) {
    // Something happened to one of my children.
    // Add error to state
    this.setState({
      error: error,
      info: info,
    });
  }

  render() {
    if(this.state.error) {
      // Some error was thrown. Let's display something helpful to the user
      return (
        <div>
          <h5>Sorry. More than five characters!</h5>
          <details style={{ whiteSpace: 'pre-wrap' }}>
            {this.state.info.componentStack}
          </details>
        </div>
      );
    }
    // No errors were thrown. As you were.
    return this.props.children;
  }
}

Nothing special right? The only new thing that we have in this component that you probably haven’t used before is the componentDidCatch method.

When an error is thrown in any of its children, the error state will be updated and a meaningful error displayed. Otherwise, the Shield will go ahead and display the children as usual.

Implementing The Error Boundary

To start using the Error Boundary, we will look at two separate scenarios.

Scenario One: Two Components within the same Error Boundary

In a situation where you have two Components within the same Error Boundary and an error is thrown in one of the Components, they are both affected due to the structure of the render method in our Shield component.

To try this out, we will add two FiveMax components inside our Shield Error Boundary.

// Shield Component

// FiveMax Component

function App() {
  return (
    <div>
      <h3>Two children under one error boundary. If one crashes. Both are affected!</h3>
      <Shield>
        <FiveMax />
        <FiveMax />
      </Shield>
    </div>
  );
}
ReactDOM.render(<App />, document.getElementById('root'));

When you try typing more than five characters into any of the fields, an error is logged on the console and we get a pleasing and more informative message displayed to the user in place of both components.

This is all good but we did not need to lose the other component that did not throw any errors. Let’s fix that!

Scenario Two: Two Components, each of them with its own Error Boundary

Now to prevent what happened in scenario one, we will have each of the FiveMax components in their own Shield Error Boundary.

// Shield Component

// FiveMax Component

function App() {
  return (
    <div>
      <h3>Two children, each with their own Error Boundary. One crashes, the other is not affected</h3>
      <Shield><FiveMax /></Shield>
      <Shield><FiveMax /></Shield>
    </div>
  );
}
ReactDOM.render(<App />, document.getElementById('root'));

Now try typing more than five characters in any of the components. Notice anything? Instead of losing both components to the error, you only lose the Component that is affected. In place of the affected component only. The rest of the App remains intact!

You can try out both scenarios in the Pen below.

See the Pen Five Max by John Kariuki (@johnkariuki) on CodePen.

Conclusion

How you use error logs entirely depends on what you want to achieve. You can have a separate Error Boundary for your navigation bar and a different one for the rest of your app so that if something goes wrong in your App’s functionality, the navigation remains usable!

Remember that if your Error Boundary throws an error, anything in its child component tree is affected. So be careful when coming up with one so that it is not prone to errors.

Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.

Learn more about us


About the authors
Default avatar
John Kariuki

author

Still looking for an answer?

Ask a questionSearch for more help

Was this helpful?
 
Leave a comment


This textbox defaults to using Markdown to format your answer.

You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!

Try DigitalOcean for free

Click below to sign up and get $200 of credit to try our products over 60 days!

Sign up

Join the Tech Talk
Success! Thank you! Please check your email for further details.

Please complete your information!

Get our biweekly newsletter

Sign up for Infrastructure as a Newsletter.

Hollie's Hub for Good

Working on improving health and education, reducing inequality, and spurring economic growth? We'd like to help.

Become a contributor

Get paid to write technical tutorials and select a tech-focused charity to receive a matching donation.

Welcome to the developer cloud

DigitalOcean makes it simple to launch in the cloud and scale up as you grow — whether you're running one virtual machine or ten thousand.

Learn more
DigitalOcean Cloud Control Panel