renderpx
Theme: auto

Error Boundaries

Catch JavaScript errors in the component tree and render a fallback UI so one failing component doesn’t crash the whole app.

The problem I keep seeing

If any component in the tree throws during render (or in a lifecycle method), React unmounts the whole tree and the user sees a blank screen. A single bug in a comment widget or a third-party chart shouldn’t take down the entire page. You need a way to catch errors in a subtree and show a fallback (message + retry) instead of crashing.

Error boundaries don’t catch errors in event handlers, async code, or server-side rendering. They only catch errors in the rendering phase (and in lifecycle methods of class components). So you still need try/catch and good error handling for async work; boundaries are for render-time failures.

Naive approach

No boundary. When a child throws, the error bubbles up and the root unmounts. The user gets a blank screen and has to refresh.

tsx
Loading...

First improvement

Wrap risky sections in a class component that implements getDerivedStateFromError and componentDidCatch. When a child throws, the boundary catches it, sets state, and renders a fallback instead of the children.

Click “Throw” to trigger the boundary

This widget is inside an Error Boundary.

Basic ErrorBoundarytsx
Loading...

Why this helps: The rest of the app (header, sidebar, footer) stays mounted. The user sees a clear message and can retry or navigate away.

Remaining issues

  • Retry: To “retry,” the boundary needs to clear its error state so it re-renders the children. Children will remount from scratch, which is usually what you want (e.g. refetch).
  • Logging: In componentDidCatch, send the error (and componentStack) to your logging service so you can fix the bug.
  • Granularity: One boundary at the root is better than nothing, but boundaries around specific features (widget, route, tab) limit blast radius and let the user keep using the rest of the app.

Production pattern

Reusable boundary that stores the caught error and exposes a reset callback so the fallback can offer “Try again.” Call reset() to set state back to no error; the boundary re-renders and mounts children again. Log in componentDidCatch. Place boundaries around route-level or feature-level chunks, not every small component.

tsx
Loading...

Why class components?

There is no hook equivalent for error boundaries. React catches errors during the render phase; hooks run in that same phase, so they can’t catch and recover. Use a thin class component that only implements the boundary API.
tsx
Loading...

When I use this

  • Use: Around route-level content, heavy third-party widgets, or any feature that might throw during render (e.g. malformed data, missing required props).
  • Root boundary: Always have at least one boundary near the root so the app never goes completely blank; show a “Something went wrong” page with refresh/retry.
  • Don’t over-wrap: Too many boundaries add complexity. Wrap at natural boundaries (route, tab, major feature), not every list item.

Gotchas

  • Event handlers: Errors in onClick or setTimeout are not caught. Use try/catch and set state (e.g. setError) to show an error UI.
  • Async errors: A rejected promise in useEffect doesn’t get caught by the boundary unless you catch it and call a state setter that triggers a re-render with a throw (not recommended). Prefer handling async errors in state and rendering an error component.
  • SSR: Error boundaries don’t catch errors during server rendering. In Next.js, use the root error.tsx and nested ones for client-side and hydration errors.

Rendering Strategy → · All patterns