DEV Community

Cover image for Resilient Architecture in React: Using Error Boundaries
Leonardo Muniz
Leonardo Muniz

Posted on

Resilient Architecture in React: Using Error Boundaries

Recently I was implementing a pdf reader for a magazine on a page, I tested it on the desktop browser and everything worked perfectly.

The problem occurred on mobile, because after going through a few pages of the pdf, the site crashed completely: "Application error: a client-side exception has occurred (see the browser console for more information).".

Console error img

Content summary

I'm not going to talk about the solution, but about how to prevent your application crashing completely in these cases, using the concept of Error Boundary to present an alternative UI in the case of an error.

Error screen not handled

Error screen not handled

UI with error boundary handling

UI with error boundary handling

Before React 16, an error in any component could result in the entire application crashing, as the error was propagated (intentionally, it's not a bug, it's a feature🫣), completely breaking the site and creating a bad user experience. With the arrival of React 16, Error Boundaries were introduced, allowing developers to capture and handle errors in specific components, without bringing down the entire application.

What are Error Boundaries? πŸ”—

Error Boundaries is a React component that catches JavaScript errors in its child components, logs those errors and displays a fallback interface instead of the failed component, working like a *catch{} for components.

Currently, it's only available as a class component and, so far, there's no evidence of the React team wanting to change this (ok, officially there isn't, but you'll find ways to do this both manually and with external libs and I'll talk about that later).

Code Example:

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

  static getDerivedStateFromError(error) {
    return { hasError: true };
  }

  componentDidCatch(error, info) {
    logErrorToService(error, info.componentStack);
  }

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

Enter fullscreen mode Exit fullscreen mode

Let's better understand the role of the functions:

  • getDerivedStateFromError: This static function is used to update the local state of the component and render a fallback UI after an error.
  • componentDidCatch: This method is triggered after an error is caught by the Error Boundary. It is useful for logging errors or side effects.

When using Error Boundary in your application, wrap the components you want to protect:

<ErrorBoundary>
  <Component />
</ErrorBoundary>
Enter fullscreen mode Exit fullscreen mode

You can also involve the entire application or you can involve the content of the site excluding the layout or even just routes, it all depends on the design you choose and which makes the most sense in your context.

When to use and when not to use πŸ”—

When to use

  • In non-critical components or functionalities.
  • When incorporating widgets or third-party libraries.

When not to use

  • For expected errors (such as known API errors).
  • Within event handlers.
  • For errors that should be handled specifically and not generically.
  • Asynchronous code: Error Boundaries do not catch errors in asynchronous operations outside of React components, such as setTimeout or requestAnimationFrame. To handle errors in asynchronous operations inside components, you must use try/catch blocks.
  • Server-side rendering
  • Errors thrown in the Error Boundary itself.

Optionals: πŸ”—

  • Integrate Error Boundaries with error monitoring solutions for quick identification and correction, you can integrate with Sentry or Exceptionless for example.
  • Test your Error Boundaries to ensure that they work as expected in different scenarios.

Third-party libraries: react-error-boundary πŸ”—
While React's native Error Boundaries are sufficient to handle these needs, some third-party libraries have been developed to simplify and enrich this functionality. One of the most popular is react-error-boundary.

Main benefits

Simplified API: With react-error-boundary, you can create an error boundary with a simple fallback function, without the need to create a component class, and it offers several other possibilities, which I won't go into today.

example with react-error-boundary:



import { ErrorBoundary } from 'react-error-boundary'

function FallbackComponent({ error }) {
  return <div>An error has occurred: {error.message}</div>
}

<ErrorBoundary FallbackComponent={FallbackComponent}>
  <Component />
</ErrorBoundary>

Enter fullscreen mode Exit fullscreen mode

Additional Hooks and Utilities: The library offers the useErrorHandler hook, which allows you to catch and handle errors within functional components and custom functions.

Automatic Restart: With the onReset property, you can define how the component should restart itself after an error.

Top comments (0)