Performance: Using error boundaries
Error boundaries affect the user experience during runtime errors by preventing full app crashes and controlling UI fallback rendering.
class ErrorBoundary extends React.Component { state = { hasError: false }; static getDerivedStateFromError() { return { hasError: true }; } render() { if (this.state.hasError) return <FallbackUI />; return this.props.children; } } function App() { return <ErrorBoundary><ComponentThatMayThrow /></ErrorBoundary>; }
function App() { return <ComponentThatMayThrow />; } // No error boundary used
| Pattern | DOM Operations | Reflows | Paint Cost | Verdict |
|---|---|---|---|---|
| No error boundary | Full React tree unmount and remount | Multiple reflows for entire app | High paint cost due to full UI redraw | [X] Bad |
| Error boundary used | Only error subtree re-renders | Single reflow limited to subtree | Lower paint cost with partial UI update | [OK] Good |
BuggyComponent throws an error?class ErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = { hasError: false };
}
static getDerivedStateFromError(error) {
return { hasError: true };
}
componentDidCatch(error, info) {
console.log('Error caught:', error);
}
render() {
if (this.state.hasError) {
return <h1>Something went wrong.</h1>;
}
return this.props.children;
}
}
// Usage
<ErrorBoundary>
<BuggyComponent />
</ErrorBoundary>BuggyComponent throws an error, getDerivedStateFromError sets hasError to true.Something went wrong. will display -> Option Dclass MyErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = { error: null };
}
componentDidCatch(error, info) {
this.setState({ error });
}
render() {
if (this.state.error) {
return <h2>Error occurred</h2>;
}
return this.props.children;
}
}Pass the test and this pattern moves unknown