Error Boundaries
Catching rendering errors in a component tree before they crash the whole app white-screen style.
2 min read
By default, a JavaScript error thrown while rendering any component unmounts the entire React tree — one broken component can blank out the whole page. An error boundary is a component that catches errors thrown by its children during rendering and shows a fallback UI instead of crashing everything.
Error boundaries must be class components
This is the one place in modern React where you still need a class — there's no Hook equivalent, because the two lifecycle methods this relies on have no function-component counterpart:
class ErrorBoundary extends React.Component {
state = { hasError: false };
static getDerivedStateFromError(error) {
return { hasError: true };
}
componentDidCatch(error, info) {
console.error("Caught by ErrorBoundary:", error, info);
}
render() {
if (this.state.hasError) {
return <h2>Something went wrong.</h2>;
}
return this.props.children;
}
}getDerivedStateFromError runs during rendering, to compute the fallback UI; componentDidCatch runs afterward, as a side effect, for logging the error to a monitoring service. Wrap it around whatever part of the tree you want isolated:
<ErrorBoundary>
<Dashboard />
</ErrorBoundary>If Dashboard or anything it renders throws while rendering, the boundary swaps in the fallback instead of the whole page going blank — and the rest of the app outside the boundary keeps working normally.
What error boundaries do NOT catch
This trips people up: error boundaries only catch errors during rendering, not:
- Errors inside event handlers (
onClick,onSubmit, etc.) — those are just normal JavaScript errors, handle them with a regulartry/catch. - Errors in asynchronous code — a
.then()callback or code after anawaitruns outside React's render cycle entirely. - Errors during server-side rendering.
- Errors thrown inside the error boundary itself.
function Button() {
function handleClick() {
throw new Error("Boom"); // NOT caught by an error boundary
}
return <button onClick={handleClick}>Click</button>;
}In practice: use a library
Writing this class by hand is boilerplate most teams skip in favor of react-error-boundary, which wraps the same mechanism in a function-component-friendly API:
import { ErrorBoundary } from "react-error-boundary";
<ErrorBoundary fallback={<p>Something went wrong.</p>}>
<Dashboard />
</ErrorBoundary>;Placement matters: one boundary around the whole app gives you a single fallback for any failure, while wrapping boundaries around individual features (a sidebar widget, a comments section) means one broken feature degrades gracefully instead of taking the rest of the page down with it.
The next lesson looks at React Server Components — a rendering model that changes some of these rules, and one that's specific to frameworks like Next.js rather than part of core React itself.