Tutorial

How To Use Error Boundaries in React

Updated on July 21, 2021
Default avatar

By William Le

How To Use Error Boundaries in React

Introduction

Error Boundaries were introduced in React v16 as a way to catch tricky errors that occur during the render phase. In the past, this would have caused the app to unmount completely, and the user would just see a blank web page, which is not ideal!

In this article, you’ll learn about Error Boundaries via code snippets and interactive demos.

Prerequisites

To follow along with this article, you will need:

This tutorial was verified with Node v16.4.2, npm v7.19.1, and react v17.0.2.

Encountering Errors without Error Boundaries

We will inevitably encounter unexpected errors in our apps during development. You could be trying to access a deeply-nested property on an object that does not exist, or sometimes it is not in your control (like a failed HTTP request to a third-party API).

In the demo below, we will simulate an error to see what normally happens without an Error Boundary.

BuggyCounter.js
import React from 'react';

class BuggyCounter extends React.Component {
  state = {
    counter: 0,
  };

  handleClick = () => {
    this.setState({
      counter: this.state.counter + 1,
    });
  };

  render() {
    if (this.state.counter === 5) {
      // Simulate an error!
      throw new Error('Simulated error.');
    }
    return (
      <div>
        <h1>{this.state.counter}</h1>
        <button onClick={this.handleClick}>+</button>
      </div>
    );
  }
}

export default BuggyCounter;

Visit the live code example alligatorio-react-error-boundaries-1 by @wle8300 on CodePen.

Click the + (increment) button and observe how it fails at 5.

Output
Uncaught Error: Simulated error.

When the app encounters an error, the component completely unmounts itself and the user is left with a blank HTML page. This can leave users feeling confused and they will not know what to do next.

Error Boundaries provide a way to gracefully handle these errors!

Encountering Errors with Error Boundaries

What are Error Boundaries exactly? Contrary to what you may think, it’s not a new component or JavaScript library. It’s more like a strategy for handling errors in React components.

Specifically, it is the usage of two methods that are available in React components:

MyErrorBoundaryExample.js
import React from 'react';

class MyErrorBoundaryExample extends React.Component {
  state = {
    error: null,
  };

  static getDerivedStateFromError(error) {
    // Update state so next render shows fallback UI.
    return { error: error };
  }

  componentDidCatch(error, info) {
    // Log the error to an error reporting service
    logErrorToExampleService(error, info);
  }

  render() {
    if (this.state.error) {
      // You can render any custom fallback UI
      return <p>Something broke</p>;
    }
    return this.props.children;
  }
}

export default MyErrorBoundaryExample;
  • static getDerivedStateFromError is a lifecycle method that allows the Error Boundary a chance to update the state and thus triggering a last render(). In the above code snippet, the state is used to reveal a human-friendly error message instead of the broken component (e.g., this.props.children).
  • componentDidCatch is a lifecycle method designed for triggering side-effects (e.g., logging the error to tools like Crashlytics). You can access info.componentStack to get a developer-friendly stack trace that will be useful for triaging the bug.

Any React Component is considered an Error Boundary when it employs at least one of these lifecycle methods.

Good practices suggest that you will want to create a component that is purpose-built as an Error Boundary instead of mixing error-handling logic into your generic components.

Let’s slightly modify <MyErrorBoundary>, and then wrap it around <BuggyComponent> so it will catch the error!

MyErrorBoundary.js
import React from 'react';

class MyErrorBoundary extends React.Component {
  state = {
    errorMessage: '',
  };

  static getDerivedStateFromError(error) {
    return { errorMessage: error.toString() };
  }

  componentDidCatch(error, info) {
    this.logErrorToServices(error.toString(), info.componentStack);
  }

  // A fake logging service.
  logErrorToServices = console.log;

  render() {
    if (this.state.errorMessage) {
      return <p>{this.state.errorMessage}</p>;
    }
    return this.props.children;
  }
}

export default MyErrorBoundary;

And App.js:

App.js
import React from 'react';
import BuggyCounter from './BuggyCounter';
import MyErrorBoudnary from './MyErrorBoundary';

class App extends React.Component {
  refreshPage = () => {
    history.go(0);
  };

  render() {
    return (
      <div>
        <MyErrorBoundary>
          <BuggyCounter />
        </MyErrorBoundary>
        <hr />
        <button onClick={this.refreshPage}>Refresh Page</button>
      </div>
    );
  }
}

export default App;

BuggyCounter.js remains the same.

Visit the live code example alligatorio-react-error-boundaries-2 by @wle8300 on CodePen.

Try clicking the + (increment) button again. Once it reaches 5, it will crash gracefully. Additionally, you can open your console to view a stack trace!

Instead of completely crashing, we can use Error Boundaries to substitute a fallback UI. This provides visual feedback to the user that something broke while allowing them to continue interacting with our app.

They can choose to navigate away or even reach out to customer service to help resolve their situation! It is a great way to redeem an otherwise unfortunate user experience.

Comparing Error Boundaries and Try...Catch

Error Boundaries actually aren’t in direct competition with try...catch statements. Error Boundaries are only designed for intercepting errors that originate from 3 places in a React component:

  • During render phase
  • In a lifecycle method
  • In the constructor

Basically… the React-y parts of a component.

As a counterpoint, these are the places where Error Boundaries will not be able to catch an error:

  • Event handlers (e.g., onClick, onChange, etc.)
  • setTimeout or requestAnimationFramecallbacks
  • Server-side rendering (SSR)
  • And errors caused by the error boundary itself (rather than its children)

So Error Boundaries don’t really impact how you use try...catch. They’re both needed as a robust strategy for handling errors in React.

Conclusion

In this article, you learned about Error Boundaries.

Note: Error Boundaries are only available in Class-based React Components. At the time of this writing, there is currently not a way to implement it using React Hooks.

Now that Error Boundaries are available since React version 16, it’s generally advisable to use at least one Error Boundary at the root of your app (e.g., the App.js file). This will prevent users from seeing a blank HTML page and perhaps see a nice fallback UI instead.

Going forward, you can employ several different kinds of Error Boundaries that employ different fallback UIs or those that only log errors to a third-party service.

Check out the official React docs for more info!

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
William Le

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