React Error Boundaries: Implementing Graceful Error Handling
Learn how to build robust React applications by implementing error boundaries. This tutorial explains how to catch and handle JavaScript errors within your component tree, preventing crashes and displaying fallback UIs for a better user experience. Master error handling in React 16 and beyond.
React Error Boundaries: Graceful Error Handling
The Problem with Unhandled Errors
Before React 16, JavaScript errors within a React component could crash the entire application. There was no built-in mechanism to catch and handle these errors gracefully.
Introducing Error Boundaries
React 16 introduced error boundaries: special components that catch JavaScript errors in their child component tree, log those errors, and display a fallback UI. This prevents the entire application from crashing due to a single error in one component.
What Error Boundaries Catch
Error boundaries catch errors during:
- Rendering
- Component lifecycle methods (e.g.,
componentDidMount
,componentDidUpdate
) - Constructors
What Error Boundaries Do *Not* Catch
- Errors in event handlers
- Errors in asynchronous code (e.g.,
setTimeout
,Promise
rejections) - Errors during server-side rendering
- Errors thrown within the error boundary itself
Implementing Error Boundaries
To create an error boundary, you need a class component that implements either static getDerivedStateFromError()
or componentDidCatch()
.
- Create a class component extending
React.Component
. - Implement
componentDidCatch(error, info)
to handle errors. This method receives the error object and additional information about where the error occurred. You can log this information to a service like Rollbar. - Implement
static getDerivedStateFromError(error)
. This method allows the component to update its state based on the caught error and display a fallback UI in the next render. - Wrap the components you want to protect with your error boundary component.
Error Boundary Example
class ErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = { hasError: false };
}
static getDerivedStateFromError(error) {
return { hasError: true };
}
componentDidCatch(error, info) {
// You can log the error here
console.error("Error caught:", error, info);
}
render() {
if (this.state.hasError) {
return <p>Something went wrong.</p>;
}
return this.props.children;
}
}
Where to Place Error Boundaries
You can place error boundaries at various levels in your component tree. Consider placing them around:
- Top-level components to protect the entire application.
- Individual components to isolate errors and prevent cascading failures.
Handling Errors in Event Handlers
Error boundaries don't catch errors within event handlers. Use a try...catch
block directly inside your event handler to handle these errors.
Uncaught Errors
If an error isn't caught by any error boundary, it will still cause the entire application to unmount.