React Error Boundary
· 約2分
Error boundaries are React components that catch Javascript errors, in their child component tree, log those errors, and display a fallback UI instead of crashing the entire app. Without them, an error in one component can bring down your whole application.
The word "boundary" emphasizes that these components create a containment zone for errors:
Error Boundaries are specifically for:
React component lifecycle errors Render method errors Constructor errors in child components
How error boundaries works
How React Rendering works
React rendering happens in two phases:
// 1. Render Phase - React calls your components
function MyComponent() {
// If error happens here...
return <div>{undefined.toString()}</div>; // 💥 Crash!
}
// 2. Commit Phase - React updates the DOM
// (If render phase succeeds)
What Makes Component Errors Special
- They Happen Inside React's Control
// React controls this execution:
function BrokenComponent() {
const user = null;
return <h1>{user.name}</h1>; // React catches this error
}
// React DOESN'T control this:
<button onClick={() => {
throw new Error(); // Happens outside React's render cycle
}}>
- Synchronous Execution
// Error boundaries can catch this (synchronous):
function Component() {
throw new Error('Sync error');
return <div />;
}
// But NOT this (asynchronous):
function Component() {
setTimeout(() => {
throw new Error('Async error'); // Outside React's try/catch
}, 1000);
return <div />;
}
Why Error Boundaries work
Usage
✅ Use Error Boundaries For
- Unexpected Runtime Errors
- Third-Party Component Errors
- Dynamic/Complex Components
❌ DON'T Use Error Boundaries For
- Expected Errors (Handle These Explicitly)
- Event Handler Errors
- Async Errors
Best Practices
- Strategic Placement
function App() {
return (
<ErrorBoundary> {/* App-level boundary */}
<Header />
<ErrorBoundary> {/* Feature-level boundary */}
<RiskyFeature />
</ErrorBoundary>
<Footer />
</ErrorBoundary>
);
}
- Granular for Isolation
<div>
{widgets.map(widget => (
<ErrorBoundary key={widget.id}> {/* Each widget isolated */}
<Widget {...widget} />
</ErrorBoundary>
))}
</div>
- Not for Control Flow
// ❌ Bad: Using error boundary for expected cases
<ErrorBoundary fallback={<LoginForm />}>
<AuthenticatedApp />
</ErrorBoundary>
// ✅ Good: Explicit control flow
{isAuthenticated ? <AuthenticatedApp /> : <LoginForm />}