C.W.K.
Stream
Lesson 03 of 07 · published

Error Boundaries — The One Class You Still Write

~11 min · error-boundary, errors, fallback

Level 0React Novice
0 XP0/54 lessons0/12 achievements
0/100 XP to next level100 XP to go0% complete
An error boundary is React's try/catch for the render tree. When a descendant throws during render, the nearest boundary catches it and shows a fallback. It's the only place in 2026 where you'll write a class component on purpose.

What an error boundary catches

An error boundary catches errors thrown during render of any descendant. It does NOT catch:

  • Errors in event handlers (handle them with try/catch inline).
  • Errors in setTimeout / promise rejections that don't surface in render (handle them at the source).
  • Errors in the boundary itself (you need a parent boundary for that).
  • Server-side render errors (handled by the framework, not the boundary).

Combined with Suspense for loading and use() for data, error boundaries cover the error third of the loading/error/success triad.

The class shape

An error boundary needs getDerivedStateFromError (sets fallback state when a child throws) and componentDidCatch (logs the error to your reporting service). Write it once, reuse everywhere.

The react-error-boundary library

The npm package react-error-boundary exports a polished version: <ErrorBoundary FallbackComponent={...} onError={...}>. It also gives you useErrorBoundary for triggering boundaries from inside async code that wouldn't otherwise reach them. Most apps use this library over hand-rolling.

Reset behavior

Once a boundary catches an error, it stays in the error state until something resets it. The library's resetErrorBoundary prop on the fallback component handles this — typically wired to a 'try again' button.

One boundary at every shippable region. The whole app inside one giant boundary is a crash page on every error. A boundary per major feature (sidebar, main panel, settings dialog) means one feature failing doesn't blank the whole UI. Match boundary granularity to your tolerance for surface-area outages.

Code

The minimal hand-rolled error boundary class·tsx
import { Component, type ReactNode } from "react";

type Props = {
  fallback: (error: Error, reset: () => void) => ReactNode;
  children: ReactNode;
};
type State = { error: Error | null };

export class ErrorBoundary extends Component<Props, State> {
  state: State = { error: null };

  static getDerivedStateFromError(error: Error): State {
    return { error };
  }

  componentDidCatch(error: Error, info: React.ErrorInfo) {
    // Report to your error tracker here.
    console.error("ErrorBoundary caught:", error, info);
  }

  reset = () => this.setState({ error: null });

  render() {
    if (this.state.error) {
      return this.props.fallback(this.state.error, this.reset);
    }
    return this.props.children;
  }
}
react-error-boundary — the polished version·tsx
import { ErrorBoundary } from "react-error-boundary";
import { Suspense } from "react";

function Fallback({ error, resetErrorBoundary }: { error: Error; resetErrorBoundary: () => void }) {
  return (
    <div role="alert" className="p-4 rounded-card bg-bg-elevated">
      <p className="text-danger font-medium">Something went wrong</p>
      <p className="text-muted text-sm mt-1">{error.message}</p>
      <button
        onClick={resetErrorBoundary}
        className="mt-3 px-3 py-1 rounded bg-brand text-bg"
      >
        Try again
      </button>
    </div>
  );
}

// Compose with Suspense — boundary OUTSIDE Suspense
// so a render error from inside Suspense is caught.
function App() {
  return (
    <ErrorBoundary FallbackComponent={Fallback}>
      <Suspense fallback={<p>Loading…</p>}>
        <Page />
      </Suspense>
    </ErrorBoundary>
  );
}

External links

Exercise

Install react-error-boundary. Wrap your bootstrap project's content in an ErrorBoundary with a friendly fallback. Trigger a render error on purpose (throw new Error('test') inside a component during render) and verify the fallback shows. Wire the reset button and confirm it returns the page to normal. Bonus: trigger an error inside an onClick handler and observe that the boundary does NOT catch it — that's the event-handler caveat in action.
Hint
The event-handler error needs useErrorBoundary().showBoundary(error) from inside the handler to forward to the boundary. Or just set local error state and render an error UI from the component itself.

Progress

Progress is local-only — sign in to sync across devices.
Spotted a bug or have feedback on this page?Report an Issue

Comments 0

🔔 Reply notifications (sign in)
Sign inPlease sign in to comment.

No comments yet — be the first.