Without an Error Boundary, an uncaught error thrown during rendering anywhere in a component tree unmounts that entire tree, potentially crashing the whole visible application down to a blank white screen — wrapping a section of the tree in an Error Boundary catches such errors, using the static getDerivedStateFromError() lifecycle method to update state and render a fallback UI instead, and componentDidCatch() to log the error details for debugging. Error Boundaries can currently only be implemented as class components, since there's no functional-component/hooks equivalent of these specific error-catching lifecycle methods, and they only catch errors thrown during rendering, in lifecycle methods, and in constructors of the components below them, not errors inside event handlers, asynchronous code, or server-side rendering.
1Understanding Error Handling with Error Boundaries
Without an Error Boundary, an uncaught error thrown during rendering anywhere in a component tree unmounts that entire tree, potentially crashing the whole visible application down to a blank white screen — wrapping a section of the tree in an Error Boundary catches such errors, using the static getDerivedStateFromError() lifecycle method to update state and render a fallback UI instead, and componentDidCatch() to log the error details for debugging. Error Boundaries can currently only be implemented as class components, since there's no functional-component/hooks equivalent of these specific error-catching lifecycle methods, and they only catch errors thrown during rendering, in lifecycle methods, and in constructors of the components below them, not errors inside event handlers, asynchronous code, or server-side rendering.
Error Boundaries do NOT catch errors thrown inside event handlers — a try/catch block around the specific risky logic in an event handler, or the handler's own error state, is still needed for those cases, since Error Boundaries are strictly about errors during rendering.
class ErrorBoundary extends React.Component {
state = { hasError: false };
static getDerivedStateFromError() {
return { hasError: true };
}
componentDidCatch(error, info) {
console.error('Caught an error:', error);
}
render() {
if (this.state.hasError) return <h2>Something went wrong.</h2>;
return this.props.children;
}
}2Practical Example
Here is a real-world application of Error Handling with Error Boundaries showing how it is used in production React code.
function BuggyComponent() {
throw new Error('Oops!');
}
function App() {
return (
<ErrorBoundary>
<BuggyComponent />
</ErrorBoundary>
);
}3Best Practices
Follow these guidelines when working with Error Handling with Error Boundaries:
1. Wrap distinct, independent sections of an application, like a sidebar widget or a specific feature area, in their own Error Boundary, so an error in one section doesn't take down the entire page
2. Use componentDidCatch() to log caught errors to an error-tracking service, so rendering crashes are visible and diagnosable in production
3. Handle errors inside event handlers with a regular try/catch block, since Error Boundaries specifically don't catch those — they only catch errors during rendering
Tip: Error Boundaries do NOT catch errors thrown inside event handlers — a try/catch block around the specific risky logic in an event handler, or the handler's own error state, is still needed for those cases, since Error Boundaries are strictly about errors during rendering.
class ErrorBoundary extends React.Component {
state = { hasError: false };
static getDerivedStateFromError() {
return { hasError: true };
}
componentDidCatch(error, info) {
console.error('Caught an error:', error);
}
render() {
if (this.state.hasError) return <h2>Something went wrong.</h2>;
return this.props.children;
}
}