Magento 2 Experten — Hyvä Theme, Tailwind CSS & SEO aus einer Hand ›

Error Boundaries in React: Catching Crashes Gracefully

Error Boundaries: Catching Crashes Gracefully

~13 Min. Lesezeit Zuletzt aktualisiert am August 8, 2026

An UNHANDLED JavaScript error while rendering a component (e.g. undefined.someProperty) crashes the ENTIRE React app by default – a white screen instead of a working application. Error boundaries prevent this by containing errors to a specific subtree.

Why plain try/catch doesn't work here

try/catch catches errors in IMPERATIVE code (function calls, loops) – but React's rendering process doesn't run inside your own try block, it runs DEEP inside React's own internal call chain. A try/catch AROUND <ProductCard /> in your own code simply does NOT catch an error that occurs WHILE rendering ProductCard.

The one remaining mandatory use of class components

A notable exception in otherwise hooks-based modern React: error boundaries MUST (as of React 18/19) be written as class components – there's no hook replacement for static getDerivedStateFromError and componentDidCatch. This is one of the few places you'll still see genuine class syntax in modern React.

src/components/ErrorBoundary.jsx
import { Component } from 'react';

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

  // Called during the render phase, right AFTER an error was thrown -
  // must return the new state, MUST NOT cause side effects (see chapter 35
  // on the render phase: it must stay "pure", even on error).
  static getDerivedStateFromError(error) {
    return { hasError: true };
  }

  // Called AFTER commit - side effects ARE allowed HERE,
  // e.g. sending the error to an error-tracking service.
  componentDidCatch(error, errorInfo) {
    console.error('ErrorBoundary caught an error:', error, errorInfo);
  }

  render() {
    if (this.state.hasError) {
      return (
        <div className="error-boundary-fallback">
          <h2>Something went wrong.</h2>
          <p>This part of the page could not be loaded.</p>
          <button onClick={() => this.setState({ hasError: false })}>
            Try again
          </button>
        </div>
      );
    }

    return this.props.children;
  }
}

export default ErrorBoundary;

The two methods in detail

  • getDerivedStateFromError is STATIC (no access to this) and runs BEFORE the next render – its sole purpose is setting state so the fallback UI shows on the next render.
  • componentDidCatch runs AFTER commit and additionally receives errorInfo (including the component stack) – actual logging/reporting belongs here, never in getDerivedStateFromError.

In practice: protecting ProductListPage against bad API responses

We'll wrap the product list with ErrorBoundary in App.jsx – should ProductListPage (or one of its children) unexpectedly crash, the rest of the app (header, navigation) stays functional:

// In App.jsx, wrap ProductListPage:
import ErrorBoundary from './components/ErrorBoundary';

// ... in the Routes:
<Route
  path="/"
  element={
    <ErrorBoundary>
      <ProductListPage />
    </ErrorBoundary>
  }
/>

Achtung: Error boundaries do NOT catch EVERYTHING: event handler errors (onClick={{() => {{ throw new Error() }} }}), asynchronous errors (setTimeout, fetch().then()), errors during server-side rendering, and errors INSIDE the error boundary component ITSELF are NOT caught. For event handler errors, regular try/catch inside the handler itself remains the right approach (see our own try/catch in ProductListPage's loadProducts() from "React for Beginners" chapter 23) – error boundaries are SPECIFICALLY for errors during rendering.

Strategic placement: not just ONE global boundary

A single ErrorBoundary at the very top around the ENTIRE app would replace the whole application with the fallback UI on ANY error – often overkill. Better: several, DELIBERATELY placed boundaries around independent page areas (like here around ProductListPage; you could similarly place one separately around CartWidget in the header) – an error in one area then doesn't take down the rest of the page with it.

Tipp: In production, componentDidCatch would typically call a service like Sentry or Bugsnag instead of just console.error – the error boundary is the ideal, central place for this, because it's GUARANTEED to see every otherwise-unhandled render error in its wrapped subtree, without every individual component needing to build in its own error handling.