React Error Boundaries
Written By: Avinash Malhotra
Updated on
In React, if an error occurs inside a component — for example, during rendering, lifecycle methods, or inside hooks — it can cause the entire app to crash.
To prevent this, React provides a special feature called Error Boundaries, which lets you catch JavaScript errors in components and show a fallback UI instead of crashing the whole app.
What is an Error Boundary?
An Error Boundary is a special React component that catches JavaScript errors in its child components and displays a fallback UI instead of crashing the entire app.
Think of it like a try...catch block, but for React components.
Why Use Error Boundaries?
Error boundaries help maintain a good user experience by preventing the app from becoming unusable due to a single component error. They allow you to:
- Catch and handle errors gracefully
- Log errors for debugging purposes
- Display user-friendly error messages
- Prevent cascading failures in the component tree
What do error boundaries do?
- Error boundaries catch errors in their children, not in themselves.
- They catch errors that happen in:
- Rendering
- Lifecycle methods
- Constructors of child components
- They do not catch errors in:
- Event handlers
- Asynchronous code (like setTimeout, fetch)
- Server-side rendering
- Errors inside the error boundary itself
Basic Error Boundary Example
Error boundaries are always written as class components (for now). Function components cannot be used as error boundaries. Here is an example below:
import React from "react";
class ErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = { hasError: false };
}
static getDerivedStateFromError(error) {
// Update state to show fallback UI
return { hasError: true };
}
componentDidCatch(error, info) {
console.error("Error caught by Error Boundary:", error);
console.info("Component stack:", info);
}
render() {
if (this.state.hasError) {
return <h2>Something went wrong.</h2>
}
return this.props.children;
}
}
export default ErrorBoundary;
In this example, the ErrorBoundary component catches errors in its child components. When an error occurs, it updates its state to show a fallback UI.
You can use this ErrorBoundary component to wrap any part of your app where you want to catch errors:
import React from "react";
import ErrorBoundary from "./ErrorBoundary";
import BuggyComponent from "./BuggyComponent";
function App() {
return (
<ErrorBoundary>
<BuggyComponent />
</ErrorBoundary>
);
}
export default App;
In this example, if BuggyComponent throws an error during rendering, the ErrorBoundary will catch it and display the fallback UI instead of crashing the entire app.
Custom Fallback UI
You can show a more meaningful UI like a reload button, a retry message, or a custom layout. Here is an example:
class ErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = { hasError: false };
}
static getDerivedStateFromError() {
return { hasError: true };
}
render() {
if (this.state.hasError) {
return (
<div>
<h2>Oops! Something went wrong.</h2>
<button onClick={() => window.location.reload()}>Reload Page</button>
</div>
);
}
return this.props.children;
}
}
In this example, if an error occurs in BuggyComponent, the ErrorBoundary will display the custom fallback UI instead of the default message.
Best Practices for Error Boundaries
- Wrap top-level components: Place error boundaries around major sections of your app to isolate errors.
- Use multiple boundaries: Different parts of your app can have their own error boundaries for granular error handling.
- Log errors: Always implement error logging in
componentDidCatchto track issues in production. - Provide meaningful fallbacks: Design fallback UIs that guide users on what to do next.
- Test error scenarios: Manually trigger errors during development to ensure boundaries work correctly.
Limitations of Error Boundaries
While powerful, error boundaries have some limitations:
- They only catch errors in React components, not in event handlers or asynchronous code.
- They cannot recover from errors automatically; they only provide a way to display fallbacks.
- Error boundaries must be class components; function components cannot be error boundaries.
- They don't catch errors in the error boundary component itself.
For comprehensive error handling, combine error boundaries with other techniques like try-catch in event handlers and proper async error handling.