Table of Contents
- Introduction
- What are Error Boundaries in React?
- Why Do We Need Error Boundaries?
- When Do Error Boundaries Catch Errors?
- Limitations: What Error Boundaries Cannot Catch
- How to Create an Error Boundary
- Practical Use Cases
- Nested Error Boundaries and Granular Recovery
- Logging Errors to Monitoring Services
- Error Boundaries in Server-Side Rendering (SSR)
- Best Practices
- Conclusion
1. Introduction
In a complex React application, unforeseen JavaScript errors can cause component trees to unmount, leading to blank screens and poor user experiences. React introduced Error Boundaries as a robust solution for catching these crashes and displaying fallback UIs—allowing apps to degrade gracefully instead of failing silently or breaking the entire UI.
This module will help you understand what Error Boundaries are, how to build and use them effectively, and best practices to ensure stability in production-grade applications.
2. What Are Error Boundaries in React?
Error Boundaries are special React components that catch JavaScript errors anywhere in their child component tree, log those errors, and render a fallback UI instead of crashing the whole application.
Introduced in React 16, they work similarly to a try-catch
block, but for React components.
They catch render-time errors, lifecycle errors, and constructor errors in class components only (at least for the error boundaries themselves).
3. Why Do We Need Error Boundaries?
Without error boundaries, a single uncaught JavaScript error in a component can:
- Break the entire React component tree
- Unmount the whole UI
- Leave users with a blank or frozen screen
Instead, with error boundaries, you can:
- Show a user-friendly fallback screen
- Isolate the error to a particular part of the UI
- Log the issue for developers to investigate
- Prevent a broken component from taking down the app
This is crucial for applications with dynamic rendering, user-generated content, or third-party integrations.
4. When Do Error Boundaries Catch Errors?
Error boundaries catch errors during the following:
- Rendering
- Lifecycle methods
- Constructors of any child component
They do not catch errors in:
- Event handlers (must use
try-catch
) - Asynchronous code like
setTimeout
,fetch
, or Promises - Server-side rendering
- Errors thrown in the Error Boundary itself
5. Limitations: What Error Boundaries Cannot Catch
Error Type | Caught by Error Boundary? |
---|---|
Rendering and lifecycle errors | ✅ |
Constructor errors in child components | ✅ |
Errors in event handlers | ❌ (handle with try-catch ) |
Async errors (e.g., fetch , Promise ) | ❌ (handle inside catch ) |
Server-side rendering (Next.js SSR) | ❌ (must use custom error pages) |
Error inside the ErrorBoundary itself | ❌ (leads to unmount) |
6. How to Create an Error Boundary
Error Boundaries must be class components, as componentDidCatch
and getDerivedStateFromError
are lifecycle methods unavailable in function components.
jsxCopyEditimport React from 'react';
class ErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = { hasError: false };
}
static getDerivedStateFromError(error) {
// Update state so fallback UI renders
return { hasError: true };
}
componentDidCatch(error, errorInfo) {
// Log the error (could also send to monitoring tools)
console.error("ErrorBoundary caught an error", error, errorInfo);
}
render() {
if (this.state.hasError) {
return <h2>Something went wrong. Please try again later.</h2>;
}
return this.props.children;
}
}
export default ErrorBoundary;
Usage:
jsxCopyEdit<ErrorBoundary>
<UserProfile />
</ErrorBoundary>
7. Practical Use Cases
- Third-party widgets: Avoid entire app breaking due to unstable libraries.
- Dynamic user input: Isolate unpredictable content components.
- Remote content rendering: When parsing or visualizing API data.
- Layout sections: Different fallback UI for header, body, and footer.
8. Nested Error Boundaries and Granular Recovery
You can nest multiple error boundaries to make the recovery more specific.
jsxCopyEdit<ErrorBoundary>
<Header />
</ErrorBoundary>
<ErrorBoundary>
<MainContent />
</ErrorBoundary>
<ErrorBoundary>
<Footer />
</ErrorBoundary>
This way, a crash in one part of the app won’t take down the others.
9. Logging Errors to Monitoring Services
In production, you should log errors using services like:
- Sentry
- LogRocket
- Datadog
- Bugsnag
Example using Sentry:
jsxCopyEditcomponentDidCatch(error, errorInfo) {
Sentry.captureException(error, { extra: errorInfo });
}
This gives you stack traces, user session data, and performance metrics.
10. Error Boundaries in Server-Side Rendering (SSR)
Error Boundaries only work in client-side React. They won’t catch errors thrown during server-side rendering (e.g., in Next.js).
For SSR, you should:
- Use Next.js
getInitialProps
orerror.js
page - Handle rendering errors in custom
_error.js
jsxCopyEdit// pages/_error.js
function Error({ statusCode }) {
return <p>Error: {statusCode}</p>;
}
Error.getInitialProps = ({ res, err }) => {
const statusCode = res ? res.statusCode : err ? err.statusCode : 404;
return { statusCode };
};
export default Error;
11. Best Practices
- Always use fallback UIs: Don’t leave users in the dark.
- Avoid hiding all errors: Show friendly but useful messages.
- Log errors for debugging: Use tools for production logging.
- Test your boundaries: Simulate crashes during QA.
- Granular wrapping: Only wrap parts of the app that may crash.
12. Conclusion
Error Boundaries are a crucial part of building stable and user-friendly React applications. They provide a mechanism to handle unforeseen crashes gracefully and ensure that your users aren’t left staring at a blank screen.
Key takeaways:
- They work only in class components (not in hooks).
- Catch errors during rendering, lifecycles, and constructors.
- Use nested boundaries for better error isolation.
- Integrate with monitoring tools for robust production logging.
- Combine with custom fallback UIs to preserve user trust.