Why Error Boundaries Matter
In React applications, a single uncaught JavaScript error in a component can crash the entire UI. Before Error Boundaries, this meant users would see a white screen with no indication of what went wrong. Error Boundaries are React components that catch JavaScript errors anywhere in their child component tree and render a fallback UI instead of crashing.
Implementing an Error Boundary
Error Boundaries are class components that implement one or both of the static lifecycle methods getDerivedStateFromError and componentDidCatch:
import React, { Component, ErrorInfo, ReactNode } from "react";
interface Props {
children: ReactNode;
fallback?: ReactNode;
}
interface State {
hasError: boolean;
error: Error | null;
}
class ErrorBoundary extends Component<Props, State> {
constructor(props: Props) {
super(props);
this.state = { hasError: false, error: null };
}
static getDerivedStateFromError(error: Error): State {
return { hasError: true, error };
}
componentDidCatch(error: Error, info: ErrorInfo) {
console.error("Error caught:", error, info.componentStack);
// Send to logging service
logErrorToService(error, info);
}
render() {
if (this.state.hasError) {
return this.props.fallback || <DefaultFallback error={this.state.error} />;
}
return this.props.children;
}
}
Fallback UI Design
A good fallback UI provides recovery options and reduces user frustration:
function DefaultFallback({ error }: { error: Error | null }) {
return (
<div role="alert" className="error-boundary-fallback">
<h2>Something went wrong</h2>
<p>We encountered an unexpected error. Please try refreshing the page.</p>
<button onClick={() => window.location.reload()}>
Refresh Page
</button>
{process.env.NODE_ENV === "development" && (
<pre>{error?.message}</pre>
)}
</div>
);
}
Integrating with Logging Services (Sentry)
Error Boundaries integrate naturally with error monitoring tools like Sentry:
import * as Sentry from "@sentry/react";
class SentryErrorBoundary extends Component<Props, State> {
componentDidCatch(error: Error, info: ErrorInfo) {
Sentry.withScope((scope) => {
scope.setExtras({ componentStack: info.componentStack });
Sentry.captureException(error);
});
}
}
Sentry also provides a built-in Error Boundary wrapper:
<Sentry.ErrorBoundary fallback={<ErrorFallback />}>
<App />
</Sentry.ErrorBoundary>
Boundary Placement Strategies
Strategic placement of Error Boundaries is crucial:
App
├── ErrorBoundary (global fallback)
│ ├── Layout
│ │ ├── Header
│ │ ├── ErrorBoundary (content area fallback)
│ │ │ ├── MainContent
│ │ │ └── DataTable
│ │ └── Footer
│ └── ErrorBoundary (sidebar fallback)
│ └── SidebarWidget
Guidelines:
- Wrap each major section (sidebar, main content, modals) independently
- Use a root boundary only as a last resort
- Place boundaries at feature boundaries where failure is recoverable
- Allow healthy parts of the UI to remain functional
Error Recovery Patterns
Beyond showing fallbacks, Error Boundaries can offer recovery:
class RecoverableBoundary extends Component {
state = { hasError: false, error: null };
static getDerivedStateFromError(error: Error) {
return { hasError: true, error };
}
handleRetry = () => {
this.setState({ hasError: false, error: null });
};
render() {
if (this.state.hasError) {
return (
<div>
<p>Error: {this.state.error?.message}</p>
<button onClick={this.handleRetry}>Retry</button>
</div>
);
}
return this.props.children;
}
}
Limitations
Error Boundaries have important limitations to understand:
| Limitation | Explanation |
|---|---|
| Event handlers | Errors in onClick etc. are NOT caught — use try-catch |
| Async code | setTimeout or Promise errors are NOT caught |
| SSR | Error Boundaries do NOT catch server-side errors |
| Own errors | An Error Boundary cannot catch its own errors |
| State mutations | Not designed to handle corrupted global state |
Conclusion
Error Boundaries are an essential part of production React applications. They prevent complete UI crashes, provide graceful degradation, and integrate seamlessly with logging services. By combining strategic boundary placement with proper error logging and recovery patterns, you can build applications that handle failures gracefully and provide actionable diagnostics for developers.
