Error Boundaries in React

Errors are a natural part of software development. In React, when a JavaScript error occurs inside a component during rendering, it can crash the entire application — leaving the user with a blank white screen. Error Boundaries are a React mechanism that catches errors in a component subtree, prevents them from crashing the whole application, and displays a fallback UI in place of the broken component.

Think of an error boundary like a safety net beneath a tightrope walker. If they fall (an error occurs), the net catches them — the entire performance does not collapse.

What Errors Do Error Boundaries Catch?

Error boundaries catch errors that occur:

  • During rendering
  • In lifecycle methods
  • In constructors of child components

They do not catch errors in:

  • Event handlers (use regular try/catch for those)
  • Asynchronous code (e.g., setTimeout, fetch)
  • Server-side rendering

Creating an Error Boundary

As of React 18, Error Boundaries must be written as class components. There is no Hook equivalent yet for the core error boundary behavior — though third-party libraries like react-error-boundary provide a functional wrapper.

An error boundary class component must implement either or both of:

  • static getDerivedStateFromError(error) — Updates state so the next render shows a fallback UI
  • componentDidCatch(error, info) — Logs the error details (e.g., to an error monitoring service)

import { Component } from 'react';

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

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

  componentDidCatch(error, info) {
    // Log the error to an error reporting service
    console.error("Error caught by boundary:", error);
    console.error("Component stack:", info.componentStack);
  }

  render() {
    if (this.state.hasError) {
      return <h2>Something went wrong. Please try refreshing the page.</h2>;
    }

    return this.props.children;
  }
}

export default ErrorBoundary;

Using an Error Boundary

Wrap any component or section of the application that might throw an error:


import ErrorBoundary from './ErrorBoundary';
import UserProfile from './UserProfile';
import ProductFeed from './ProductFeed';

function App() {
  return (
    <div>
      <ErrorBoundary>
        <UserProfile />
      </ErrorBoundary>

      <ErrorBoundary>
        <ProductFeed />
      </ErrorBoundary>
    </div>
  );
}

If UserProfile throws an error, only that section shows the fallback message. ProductFeed continues to work normally. The rest of the application is unaffected.

Customizing the Fallback UI

A more flexible error boundary accepts a custom fallback as a prop:


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

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

  componentDidCatch(error, info) {
    console.error(error, info);
  }

  render() {
    if (this.state.hasError) {
      return this.props.fallback || <p>Something went wrong.</p>;
    }
    return this.props.children;
  }
}

<ErrorBoundary fallback={<div><h3>Widget unavailable</h3><p>This section failed to load.</p></div>}>
  <WeatherWidget />
</ErrorBoundary>

Using react-error-boundary (Recommended for Modern Apps)

The react-error-boundary package provides a functional, modern API for error boundaries without writing class components:


npm install react-error-boundary

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

function FallbackComponent({ error, resetErrorBoundary }) {
  return (
    <div>
      <h3>An error occurred:</h3>
      <p>{error.message}</p>
      <button onClick={resetErrorBoundary}>Try Again</button>
    </div>
  );
}

function App() {
  return (
    <ErrorBoundary FallbackComponent={FallbackComponent}>
      <MyComponent />
    </ErrorBoundary>
  );
}

The resetErrorBoundary function resets the error state and attempts to re-render the failed component — useful for "Try Again" buttons that allow users to recover from transient errors.

Strategic Placement of Error Boundaries

Placing a single error boundary at the very top of the application would catch all errors — but the entire UI would be replaced with the fallback. A better strategy is to place error boundaries around individual sections so only the broken section is affected:

  • Wrap each major page or section separately
  • Wrap third-party widgets or external data components individually
  • Wrap each route separately when using React Router

Key Points

  • Error boundaries prevent a single component error from crashing the entire application.
  • They must currently be written as class components using getDerivedStateFromError and/or componentDidCatch.
  • The react-error-boundary package provides a modern, functional alternative.
  • Only errors during rendering and lifecycle methods are caught — not event handler or async errors.
  • Place error boundaries around individual sections, not just at the root, for better user experience.
  • Use resetErrorBoundary to allow users to attempt recovery after an error.

The next topic covers Higher Order Components (HOC) — a pattern for reusing component logic by wrapping components with additional behavior.

Leave a Comment

Your email address will not be published. Required fields are marked *