Error Boundary State Management
An error boundary commonly keeps an `hasError` flag in component state and switches to fallback UI after a descendant throws during rendering. The boundary can update that state with `static getDerivedStateFromError`, while `componentDidCatch` is typically used for side effects such as logging.
An error boundary is a React component that catches rendering errors in its descendant tree and replaces the failed subtree with fallback UI. In the common class-component pattern, state contains a flag such as `hasError` that starts as `false` and becomes `true` when an error is captured.
`static getDerivedStateFromError(error)` is used to derive the state needed for rendering fallback content. Because it participates in rendering, it should be kept free of side effects. A typical implementation returns `{ hasError: true }` regardless of the specific error.
`componentDidCatch(error, errorInfo)` runs after an error has been caught and is appropriate for side effects such as sending diagnostic information to an error-reporting service. The state transition and logging concerns are therefore separated: one determines what the user sees, while the other records what happened.
An error boundary does not catch every possible JavaScript failure. In particular, boundaries do not catch errors from event handlers, asynchronous callbacks, server-side rendering, or errors thrown inside the boundary itself. Those cases need other error-handling mechanisms.
A boundary normally remains in its fallback state until its state changes or the boundary is remounted. Recovery therefore requires an explicit strategy, such as resetting state when a relevant input changes or remounting the boundary with a new `key`.
Key points
- Store failure state such as `hasError` to control fallback rendering.
- Use `getDerivedStateFromError` to update render-related error state.
- Use `componentDidCatch` for logging and other side effects.
- Error boundaries catch errors in descendant rendering, lifecycle methods, and constructors, but not every asynchronous or event-handler error.
- Recovery requires deliberately resetting the boundary state or remounting it.
Interview questions
How does an error boundary use state to render fallback UI?
The boundary starts with state such as `hasError: false`. When a descendant throws an error that the boundary can catch, `getDerivedStateFromError` returns a new state with `hasError: true`. The next render checks that flag and returns fallback content instead of the normal children.
What is the difference between `getDerivedStateFromError` and `componentDidCatch`?
`getDerivedStateFromError` is a static lifecycle used to derive state after an error so the next render can display fallback UI. `componentDidCatch` receives the error and component stack after capture and is intended for side effects such as logging. Keeping those responsibilities separate makes the rendering transition predictable and the diagnostic work explicit.
What kinds of errors do React error boundaries not catch?
Error boundaries do not catch errors in event handlers, asynchronous callbacks such as later timer or promise callbacks, server-side rendering, or errors thrown within the boundary itself. Event-handler failures should generally be handled in the event logic, while asynchronous failures often need explicit promise or task error handling. This distinction prevents treating a rendering error boundary as a universal JavaScript exception handler.
How would you let a user recover from an error boundary fallback?
Recovery requires changing the condition that caused the failure or resetting the boundary's error state. A common approach is to remount the boundary with a new `key`, which creates a fresh instance with its initial state. Another design is to expose a reset mechanism that clears the boundary state when the user retries or when relevant input changes.
Why should an error boundary separate fallback rendering from error reporting?
Fallback rendering is part of React's recovery path, so it should remain deterministic and focused on producing safe UI. Error reporting is a side effect and can be handled in `componentDidCatch`, where the error and component stack are available. Separating them also makes it easier to change monitoring behavior without coupling it to the rendering decision.