Error Boundary React Design Pattern
A single undefined.map() in one widget crashed my entire React app. The user saw a white screen. No error message. No way to recover. A bug in the sidebar...
15 Apr 2024

A single undefined.map() in one widget crashed my entire React app. The user saw a white screen. No error message. No way to recover. A bug in the sidebar took down the whole page.
Error Boundaries prevent that. They catch JavaScript errors in their child component tree and display a fallback UI instead of crashing everything.
Think of it like circuit breakers in your house. A short circuit in the kitchen doesn't kill power to the entire house. The breaker trips, the kitchen goes dark, and everything else keeps running.
The Catch: Class Components Required
React's componentDidCatch and getDerivedStateFromError lifecycle methods only work in class components. There's no hook equivalent. This is one of the few cases where class components are still necessary.
import React, { Component } from 'react';
class ErrorBoundary extends Component {
constructor(props) {
super(props);
this.state = { hasError: false };
}
static getDerivedStateFromError(error) {
return { hasError: true };
}
componentDidCatch(error, errorInfo) {
console.error('Error caught by boundary:', error, errorInfo);
// Send to your error tracking service (Sentry, LogRocket, etc.)
}
render() {
if (this.state.hasError) {
return this.props.fallback || <h1>Something went wrong.</h1>;
}
return this.props.children;
}
}
export default ErrorBoundary;
Wrap any section of your app:
import ErrorBoundary from './ErrorBoundary';
import Dashboard from './Dashboard';
import Sidebar from './Sidebar';
const App = () => (
<div>
<ErrorBoundary fallback={<p>Sidebar failed to load.</p>}>
<Sidebar />
</ErrorBoundary>
<ErrorBoundary fallback={<p>Dashboard failed to load.</p>}>
<Dashboard />
</ErrorBoundary>
</div>
);
Now a crash in Sidebar shows the fallback message while Dashboard keeps working.
What Error Boundaries Don't Catch
- Event handlers (use try/catch inside them)
- Async code (promises, setTimeout)
- Server-side rendering errors
- Errors in the boundary itself
Error boundaries only catch errors during rendering, lifecycle methods, and constructors of the tree below them.
Placement Strategy
Don't wrap your entire app in one boundary. That's a single giant circuit breaker — it defeats the purpose. Instead, wrap independent sections: each route, each widget, each third-party integration. The more granular your boundaries, the more resilient your app.
The benefit: Graceful degradation. Users see a helpful message instead of a blank page. You can log errors to a tracking service for debugging. The rest of the app stays functional.
The cost: Class component boilerplate in a hooks world. Error boundaries don't catch async errors, so you still need try/catch for event handlers and API calls. And the fallback UI needs design effort — a generic "something went wrong" message isn't great UX.
I wrap every major section of my apps with an error boundary. For libraries like react-error-boundary, you get a cleaner API with hooks-like ergonomics and retry functionality built in.