How React catches errors in the component tree and renders fallback UI.
Error boundaries are React class components that catch JavaScript errors anywhere in their child component tree, log those errors, and display a fallback UI instead of crashing the entire application. They work like a JavaScript catch{'} block, but for the component tree. An error boundary catches errors during rendering, in lifecycle methods, and in constructors of the whole tree below it.
When any component in the subtree throws during rendering (or in a lifecycle method), React starts propagating the error upward through the fiber tree, looking for the nearest error boundary.
React traverses up through parent fibers. If it finds a class component that implements getDerivedStateFromError or componentDidCatch, it stops there. If it reaches the root without finding one, the entire app unmounts.
React calls getDerivedStateFromError(error) on the boundary class. This static method returns new state (e.g., '{' hasError: true '}') which causes the boundary to re-render with the fallback UI.
After the fallback UI is shown, React calls componentDidCatch(error, errorInfo) β a good place to send the error to a logging service like Sentry.
The boundary component checks its state (hasError) and renders either the children (normal) or a fallback JSX element. The rest of the app outside the boundary continues to work normally.
Static class method. Called during render phase when a child throws. Returns new state to trigger fallback rendering.
Instance method. Called during commit phase after fallback is rendered. Use for error logging. Receives error + component stack.
Errors bubble up through the fiber tree to the nearest boundary, just like exceptions bubble up through call stacks.
Boundaries can be reset by changing their key prop, which causes React to unmount and remount the entire subtree fresh.
1class ErrorBoundary extends React.Component {2 state = { hasError: false, error: null };34 static getDerivedStateFromError(error) {5 // Called during render β must be pure, no side effects6 return { hasError: true, error };7 }89 componentDidCatch(error, info) {10 // Called after commit β safe for side effects like logging11 logErrorToSentry(error, info.componentStack);12 }1314 render() {15 if (this.state.hasError) {16 return <FallbackUI error={this.state.error} />;17 }18 return this.props.children;19 }20}2122// Usage:23<ErrorBoundary>24 <MyComponent /> {/* If this throws, ErrorBoundary catches it */}25</ErrorBoundary>
Without error boundaries, a single unhandled render error crashes your entire React app and shows a blank screen. Error boundaries let you quarantine failures to isolated sections of the UI β the rest of the app keeps working. This is critical for production apps where you can't predict every edge case.
Your e-commerce app crashes in production when a product with malformed data renders. The entire page goes white and users see nothing β you lose the sale and have no visibility into what happened.
Without error boundaries, a single component throwing an error unmounts the ENTIRE React tree. The user sees a blank page. No error tracking fires because the crash happened during rendering, not in a try/catch block.
Wrap critical sections in error boundaries with strategic granularity: one around the product card, one around the cart, one around the whole page. Use componentDidCatch to send the error + componentStack to Sentry. Show a helpful fallback UI ('Something went wrong, refresh to try again') instead of a blank page.
Takeaway: Error boundaries are your PRODUCTION safety net. Place them at route level (catch everything), feature level (isolate failures), and widget level (for third-party components you don't control). Always log to an error tracking service in componentDidCatch.
You embed a third-party analytics chart widget in your dashboard. After a library update, the widget occasionally throws during rendering due to unexpected data formats.
The chart crash cascades β it's nested inside your dashboard layout, so the error propagates up and takes down the entire dashboard, including the navigation, sidebar, and all other widgets.
Wrap ONLY the third-party widget in its own error boundary. The fallback shows a placeholder ('Chart unavailable β refresh to retry'). The rest of the dashboard remains fully functional. Users can still use all other features while you investigate the chart issue.
Takeaway: Error boundaries give you component-level fault isolation, similar to microservice circuit breakers. Treat each third-party or unstable component as an isolated fault domain.