Error Boundaries.

54 views

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:

import React from 'react'
 
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
  }
}

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>

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 🔗

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
  }
}

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>

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