React Error Boundaries Explained — Graceful Error Handling
In this tutorial, you will learn about React Error Boundaries Explained. We cover key concepts, practical examples, and best practices to help you master this topic.
React error boundaries are components that catch JavaScript errors anywhere in their child component tree, log those errors, and display a fallback UI instead of crashing the whole app.
What You'll Learn
- What error boundaries catch (and what they miss)
- How to create a class-based error boundary
- How to use react-error-boundary library
- How to log errors to external services
- How to recover from errors
Why It Matters
Without error boundaries, a single error in any component crashes the entire React app. Error boundaries contain failures, letting the rest of the app continue working.
Real-World Use
Durga Antivirus Pro wraps each dashboard widget in an error boundary. If the ThreatGraph component crashes, only that widget shows an error state while the rest of the dashboard continues functioning.
flowchart TD
A[App] --> B[ErrorBoundary]
B --> C[Sidebar]
B --> D[ErrorBoundary]
D --> E[ThreatGraph]
D --> F[ErrorBoundary]
F --> G[ScanStatus]
style B fill:#3b82f6,color:#fff
style D fill:#3b82f6,color:#fff
style F fill:#3b82f6,color:#fff
Creating an Error Boundary
Error boundaries must be class components (hooks do not support it yet):
import { Component } from "react";
class ErrorBoundary extends Component {
constructor(props) {
super(props);
this.state = { hasError: false, error: null, errorInfo: null };
}
static getDerivedStateFromError(error) {
return { hasError: true, error };
}
componentDidCatch(error, errorInfo) {
console.error("Error caught:", error, errorInfo);
this.setState({ errorInfo });
if (this.props.onError) {
this.props.onError(error, errorInfo);
}
}
render() {
if (this.state.hasError) {
if (this.props.fallback) {
return this.props.fallback;
}
return (
<div className="error-boundary" style={{ padding: 20, background: "#fef2f2", borderRadius: 8, border: "1px solid #fecaca" }}>
<h2>Something went wrong</h2>
<p>{this.state.error?.message || "An unexpected error occurred."}</p>
<button onClick={() => this.setState({ hasError: false, error: null })}>
Try again
</button>
</div>
);
}
return this.props.children;
}
}
function Widget({ name }) {
if (name === "broken") throw new Error("Widget failed to load");
return <div>{name} widget loaded successfully</div>;
}
function App() {
return (
<div>
<ErrorBoundary fallback={<p>Sidebar crashed</p>}>
<Widget name="sidebar" />
</ErrorBoundary>
<ErrorBoundary>
<Widget name="broken" />
</ErrorBoundary>
<ErrorBoundary>
<Widget name="footer" />
</ErrorBoundary>
</div>
);
}
Expected output: The sidebar and footer render normally. The broken widget shows an error boundary fallback.
Error boundaries catch errors during rendering, lifecycle methods, and constructors. They do NOT catch errors in event handlers, async code, or server-side rendering.
Common Mistakes
- Assuming error boundaries catch async errors
- Not wrapping each independent section separately
- Forgetting to provide a useful fallback UI
- Not logging errors for debugging
- Rendering the error boundary itself throws
Practice Questions
- What errors do error boundaries catch?
- What errors do error boundaries NOT catch?
- Why must error boundaries be class components?
- How do you reset an error boundary?
- How do you log errors from error boundaries?
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro