codejump

AcademyReact

Error Boundaries

Why a render error unmounts the whole tree by default, how a class component catches it, and what it never catches at all.

3 min readUpdated

3 exercises

Waiting at the end of this page.

The default is total

Throw an error while rendering — in a component body, in render, in a constructor, anywhere below the root — and React does not leave the broken part on screen. It unmounts the entire tree.

That sounds harsh until you compare it with the alternative. A component that half-rendered after failing partway through is not "mostly working" — it is showing a user data it never finished computing, with no way to tell which parts are real. React's authors decided a blank screen is a more honest failure than a plausible-looking wrong one, and Error Boundaries exist to opt back into something less than "blank screen, whole app."

The only class component you still need to write

There is no hook for this. componentDidCatch and getDerivedStateFromError are lifecycle methods on a class component, and nothing in the Hooks API replaces them:

JSX
class ErrorBoundary extends React.Component {
  state = { hasError: false };

  static getDerivedStateFromError() {
    // Called during render, after a descendant threw. Return the state
    // that produces the fallback UI on the next render.
    return { hasError: true };
  }

  componentDidCatch(error, info) {
    // Called after render, with the commit already rolled back. This is
    // where you report to Sentry — never inside getDerivedStateFromError,
    // which must stay a pure function of the error.
    logErrorToService(error, info.componentStack);
  }

  render() {
    if (this.state.hasError) return this.props.fallback;
    return this.props.children;
  }
}

The split matters: getDerivedStateFromError decides what to render and must be pure — no logging, no network calls. componentDidCatch is the side-effecting half, called once the fallback has already committed. Mixing the two — logging inside getDerivedStateFromError, or trying to set fallback state from componentDidCatch — works by accident on some React versions and breaks on others.

What it does not catch

This is the part that costs people in interviews, because the name suggests more coverage than it has. An Error Boundary catches errors thrown during React's own rendering work for its descendants, and nothing else:

SourceCaught?What actually handles it
Error thrown in a component's render bodyYesThe boundary
Error thrown in a lifecycle method / effect setupYesThe boundary
Error thrown inside an onClick handlerNotry/catch in the handler itself
A rejected promise from fetchNo.catch() on the promise
An error thrown by the boundary component itselfNoA boundary higher up than this one
An error during server-side renderingNoFramework-level SSR error handling

Event handlers run outside React's render call stack entirely — by the time onClick fires, rendering already finished, so there is no render pass for the boundary to intercept. Same story for anything async: the throw happens in a microtask or a timer callback, far from any component that is currently rendering. Both need their own explicit handling; a boundary sitting above them does nothing for either.

Where to put them

One Error Boundary at the app root buys you a global fallback — "Something went wrong, reload" — instead of a white screen. That is necessary but not sufficient. If the only boundary in the app sits at the root, one broken widget takes the whole page down with it.

JSX
function Dashboard() {
  return (
    <Layout>
      <ErrorBoundary fallback={<ChartError />}>
        <RevenueChart />
      </ErrorBoundary>
      <ErrorBoundary fallback={<ChartError />}>
        <UserGrowthChart />
      </ErrorBoundary>
    </Layout>
  );
}

Each chart gets its own boundary. A bad API response that crashes RevenueChart now shows one broken tile instead of an empty page — UserGrowthChart keeps rendering because its own render pass was never touched. The rule of thumb: put a boundary around any subtree whose failure should not be correlated with its siblings' success.

Now practice it

2 challenges · 1 quiz

Reading this page is the cheap half. These are the exercises that make you use it.