Even well-tested applications encounter unexpected errors. A component may receive unexpected data, a third-party widget may fail, or a rendering path may contain an overlooked edge case.
Without an appropriate recovery strategy, a rendering error can make a large portion of the interface unusable. React error boundaries help contain certain rendering failures and provide a fallback interface.
What Error Boundaries Catch
Error boundaries catch errors that occur while rendering descendant components and during relevant lifecycle processing.
They do not automatically catch every kind of error. In particular, ordinary event-handler errors, most asynchronous callback errors, and server-side rendering errors need their own handling strategies.
This distinction matters because an error boundary is not a universal replacement for error handling.
Create a Boundary
A class component can implement an error boundary using getDerivedStateFromError and optionally componentDidCatch.
import React from "react";
class ErrorBoundary extends React.Component {
state = { hasError: false };
static getDerivedStateFromError() {
return { hasError: true };
}
componentDidCatch(error, info) {
// Send diagnostic information to an error-reporting service.
console.error("Component rendering failed", error, info);
}
render() {
if (this.state.hasError) {
return (
<section role="alert">
<h2>Something went wrong.</h2>
<p>Please try again or return to the previous page.</p>
</section>
);
}
return this.props.children;
}
}
export default ErrorBoundary;
Wrap a section of the application:
<ErrorBoundary>
<ReportsDashboard />
</ErrorBoundary>
If a descendant throws during rendering, the boundary displays its fallback instead of allowing the failure to propagate through the entire component tree.
Choose the Right Boundary Placement
One global boundary is useful as a last line of defense, but it may not provide the best experience for every feature.
Consider separate boundaries around independent areas such as:
- Analytics dashboards.
- Rich text editors.
- Third-party integrations.
- Complex visualizations.
- Optional recommendation panels.
A failure in an optional chart should not necessarily prevent a user from accessing the rest of a dashboard.
At the same time, avoid wrapping every tiny component in its own boundary without a clear recovery strategy. Boundary placement should reflect meaningful UI sections.
Provide a Useful Recovery Path
A fallback should explain the situation without exposing sensitive internal details. Depending on the feature, it may offer a retry button, a navigation option, or a link to support.
Resetting the boundary state alone does not guarantee that the underlying error is fixed. A retry should be meaningful—for example, by refreshing data or remounting a failed section.
For production applications, capture diagnostic information in a controlled logging service. Avoid displaying raw stack traces or private request data to end users.
Handle Other Errors Separately
An error boundary will not catch a failed fetch() request merely because the request was initiated by a component. Network operations should still handle rejected promises and update the UI with loading, success, and failure states.
Similarly, form submission errors belong in the submission flow, while routing and server-rendering errors may require framework-specific handling.
Modern React frameworks often provide their own error-boundary conventions, so follow the framework’s recommended approach when using one.
Conclusion
Error boundaries help React applications fail gracefully by containing rendering errors within selected parts of the component tree. Place them around meaningful UI sections, provide useful fallback experiences, and pair them with explicit handling for network and event-driven failures.
A resilient interface does not prevent every error; it limits the damage and gives users a clear next step.