How to Update Error Boundaries in React

React Error Boundaries are essential tools for catching JavaScript errors in child component trees, preventing the entire application from crashing. This article explains how to implement, update, and reset Error Boundaries in modern React applications, covering both traditional class-based implementations and the modern, hook-compatible react-error-boundary library.

Understanding the Classic Error Boundary

Historically, React requires class components to define Error Boundaries, as the hook equivalents for getDerivedStateFromError and componentDidCatch do not yet exist.

An Error Boundary updates its state when an error is thrown using the static method getDerivedStateFromError().

import React, { Component } from 'react';

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

  static getDerivedStateFromError(error) {
    // Update state so the next render will show the fallback UI.
    return { hasError: true, error };
  }

  componentDidCatch(error, errorInfo) {
    // You can also log the error to an error reporting service
    console.error("Logging error:", error, errorInfo);
  }

  render() {
    if (this.state.hasError) {
      // You can render any custom fallback UI
      return (
        <div>
          <h2>Something went wrong.</h2>
          <p>{this.state.error?.message}</p>
        </div>
      );
    }

    return this.props.children;
  }
}

export default ErrorBoundary;

How to Update and Reset the Error State

A common requirement is updating the Error Boundary so users can “try again” or recover from the error without refreshing the entire browser tab.

To update the error state back to normal, you must implement a reset mechanism within the class component.

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

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

  handleReset = () => {
    // Reset the error state to allow re-rendering of children
    this.setState({ hasError: false });
  };

  render() {
    if (this.state.hasError) {
      return (
        <div>
          <h2>An error occurred.</h2>
          <button onClick={this.handleReset}>Try Again</button>
        </div>
      );
    }

    return this.props.children;
  }
}

Updating to Modern Functional React

To update your codebase to use functional components and React Hooks, you should use the industry-standard react-error-boundary library. This wrapper library allows you to manage and update error states without writing class components.

First, install the package:

npm install react-error-boundary

Implementing ErrorBoundary with Fallback and Reset

The ErrorBoundary component from this library accepts a FallbackComponent and an onReset prop, making it easy to update the component state when a user attempts to recover.

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

function ErrorFallback({ error, resetErrorBoundary }) {
  return (
    <div role="alert">
      <p>Something went wrong:</p>
      <pre>{error.message}</pre>
      <button onClick={resetErrorBoundary}>Try again</button>
    </div>
  );
}

function App() {
  return (
    <ErrorBoundary
      FallbackComponent={ErrorFallback}
      onReset={() => {
        // Reset the state of your app here so the error doesn't happen again
        console.log("App state reset successfully");
      }}
    >
      <MyBuggyComponent />
    </ErrorBoundary>
  );
}

Updating State Automatically on Navigation

You can also update the error boundary state automatically when specific values change (like a route change or a state variable change) using the resetKeys prop.

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

function App() {
  const [someState, setSomeState] = useState("initial");

  return (
    <ErrorBoundary
      FallbackComponent={ErrorFallback}
      // When 'someState' changes, the Error Boundary automatically resets
      resetKeys={[someState]}
    >
      <MyBuggyComponent stateValue={someState} />
    </ErrorBoundary>
  );
}