Error Boundaries
Catch rendering errors in a subtree and show a fallback instead of crashing.
An Error Boundary catches JavaScript errors thrown while rendering its child tree, logs them, and shows a fallback UI instead of unmounting the whole app.
Notes
- Error boundaries are the one place React still needs a class component, using
getDerivedStateFromErrorandcomponentDidCatch. - Most teams use the
react-error-boundarypackage for a friendly function-based API. - They do not catch errors in event handlers or async code — handle those with try/catch.
Example
import { Component } from 'react';
class ErrorBoundary extends Component {
state = { hasError: false };
static getDerivedStateFromError() {
return { hasError: true };
}
componentDidCatch(error, info) {
console.error(error, info);
}
render() {
if (this.state.hasError) return <p>Something went wrong.</p>;
return this.props.children;
}
}
function App() {
return (
<ErrorBoundary>
<Widget />
</ErrorBoundary>
);
}When to use it
- A widget dashboard wraps each chart in its own error boundary so a crash in the Revenue chart shows a 'Chart unavailable' fallback without crashing the other charts.
- A route-level error boundary catches rendering errors from any page component and shows a generic 'Something went wrong' UI instead of a blank white screen.
- A third-party map library is wrapped in an error boundary so if the library throws during initialization the rest of the page continues to function.
More examples
Class-based error boundary
Implements the required class-based error boundary with getDerivedStateFromError and componentDidCatch.
import { Component } from 'react';
class ErrorBoundary extends Component {
state = { hasError: false };
static getDerivedStateFromError() {
return { hasError: true };
}
componentDidCatch(error, info) {
console.error('Caught:', error, info.componentStack);
}
render() {
if (this.state.hasError) {
return <p className="error-fallback">Something went wrong.</p>;
}
return this.props.children;
}
}Wrap a widget in a boundary
Gives each chart widget its own error boundary so a crash in one does not affect the other.
import ErrorBoundary from './ErrorBoundary';
import RevenueChart from './RevenueChart';
function Dashboard() {
return (
<div className="dashboard">
<ErrorBoundary>
<RevenueChart />
</ErrorBoundary>
<ErrorBoundary>
<UsersChart />
</ErrorBoundary>
</div>
);
}Error boundary with reset
Adds a Retry button that increments a key to force React to remount the child tree, clearing the error.
import { Component } from 'react';
class RetryBoundary extends Component {
state = { hasError: false, key: 0 };
static getDerivedStateFromError() { return { hasError: true }; }
retry = () => this.setState(s => ({ hasError: false, key: s.key + 1 }));
render() {
if (this.state.hasError) {
return (
<>
<p>Failed to load.</p>
<button onClick={this.retry}>Try again</button>
</>
);
}
return <div key={this.state.key}>{this.props.children}</div>;
}
}
Discussion