Error boundaries are React components that catch JavaScript errors anywhere in their child component tree, log those errors, and display a fallback UI instead of crashing the whole application. Error boundaries only catch errors in the components below them in the tree and can't recover from their own errors.
Starting from React 16, errors that were not caught by any error boundary will result in unmounting of the whole React component tree, so it's important to use error boundaries to provide a better user experience.
Below is a component that will throw an error when its counter reaches 5. The error boundary catches the error and displays a fallback UI.
This example demonstrates React Error Boundaries that catch errors in components.
Click the button until it reaches 5, and the error boundary will catch the error.
0
This version uses a custom fallback UI and can reset itself.
0
Key points about Error Boundaries:
// ErrorBoundary.tsx
import React, { Component, ErrorInfo, ReactNode } from "react";
interface ErrorBoundaryProps {
children: ReactNode;
}
interface ErrorBoundaryState {
hasError: boolean;
error: Error | null;
}
export class ErrorBoundary extends Component<ErrorBoundaryProps, ErrorBoundaryState> {
constructor(props: ErrorBoundaryProps) {
super(props);
this.state = { hasError: false, error: null };
}
// Called when an error is thrown in a child component
static getDerivedStateFromError(error: Error): ErrorBoundaryState {
// Update state to trigger fallback UI
return { hasError: true, error };
}
// Log the error to an error reporting service
componentDidCatch(error: Error, errorInfo: ErrorInfo): void {
console.error("Error caught by ErrorBoundary:", error, errorInfo);
// You could also log to an error reporting service here
// logErrorToService(error, errorInfo);
}
render(): ReactNode {
if (this.state.hasError) {
// Fallback UI
return (
<div className="p-4 bg-red-50 border border-red-200 rounded-lg">
<h3 className="text-lg font-semibold text-red-700 mb-2">
Something went wrong
</h3>
<p className="text-red-600 mb-4">
{this.state.error?.message}
</p>
<button
onClick={() => this.setState({ hasError: false, error: null })}
className="px-3 py-1 bg-red-600 text-white rounded hover:bg-red-700 text-sm"
>
Try Again
</button>
</div>
);
}
// If no error, render children normally
return this.props.children;
}
}
// Usage:
// <ErrorBoundary>
// <ComponentThatMightThrow />
// </ErrorBoundary>