Error Boundaries
MedError boundaries are React components that catch JavaScript errors in their child component tree during rendering, in lifecycle methods, and in constructors, then display a fallback UI. They prevent a single component crash from taking down the entire application.
Interactive Visualization
Key Points
- Implemented as class components using getDerivedStateFromError and componentDidCatch
- Catch errors during rendering, lifecycle methods, and constructors
- Do NOT catch errors in event handlers, async code, or SSR
- Place boundaries strategically: route-level, feature-level, or widget-level
- componentDidCatch receives error info including the component stack trace
- Cannot be implemented as functional components (no hook equivalent yet)
Code Examples
Error Boundary Component
import { Component, type ReactNode, type ErrorInfo } from 'react' interface ErrorBoundaryProps { children: ReactNode fallback: ReactNode onError?: (error: Error, info: ErrorInfo) => void } interface ErrorBoundaryState { hasError: boolean error: Error | null } class ErrorBoundary extends Component<ErrorBoundaryProps, ErrorBoundaryState> { state: ErrorBoundaryState = { hasError: false, error: null } static getDerivedStateFromError(error: Error): ErrorBoundaryState { return { hasError: true, error } } componentDidCatch(error: Error, info: ErrorInfo): void { this.props.onError?.(error, info) } render() { if (this.state.hasError) return this.props.fallback return this.props.children } } // Usage: isolate crash zones function App() { return ( <ErrorBoundary fallback={<p>App crashed. Please refresh.</p>}> <Header /> <ErrorBoundary fallback={<p>Widget failed to load.</p>}> <UnstableWidget /> </ErrorBoundary> <Footer /> </ErrorBoundary> ) }
Nested boundaries let you isolate failures: a widget crash shows a local fallback without taking down the header or footer
Resettable Error Boundary
import { Component, type ReactNode, type ErrorInfo } from 'react' interface ResettableErrorBoundaryProps { children: ReactNode resetKey: string | number } interface ResettableErrorBoundaryState { hasError: boolean } class ResettableErrorBoundary extends Component< ResettableErrorBoundaryProps, ResettableErrorBoundaryState > { state: ResettableErrorBoundaryState = { hasError: false } static getDerivedStateFromError(): ResettableErrorBoundaryState { return { hasError: true } } componentDidUpdate(prevProps: ResettableErrorBoundaryProps): void { if (prevProps.resetKey !== this.props.resetKey && this.state.hasError) { this.setState({ hasError: false }) } } componentDidCatch(error: Error, info: ErrorInfo): void { // Log to error reporting service } render() { if (this.state.hasError) { return <button onClick={() => this.setState({ hasError: false })}>Retry</button> } return this.props.children } }
A resetKey prop lets the boundary recover when data changes, and a retry button lets users attempt recovery manually
Common Mistakes
- Expecting error boundaries to catch errors in event handlers or async code
- Placing a single boundary at the root instead of granular boundaries around risky features
- Not logging errors to an external service in componentDidCatch
Interview Tips
- Know exactly what error boundaries catch and what they do not
- Explain the strategy of multiple boundaries at different granularity levels
- Discuss how to handle errors in event handlers with try-catch and local state