Error Boundaries in React
Errors are a natural part of software development. In React, when a JavaScript error occurs inside a component during rendering, it can crash the entire application — leaving the user with a blank white screen. Error Boundaries are a React mechanism that catches errors in a component subtree, prevents them from crashing the whole application, and displays a fallback UI in place of the broken component.
Think of an error boundary like a safety net beneath a tightrope walker. If they fall (an error occurs), the net catches them — the entire performance does not collapse.
What Errors Do Error Boundaries Catch?
Error boundaries catch errors that occur:
- During rendering
- In lifecycle methods
- In constructors of child components
They do not catch errors in:
- Event handlers (use regular try/catch for those)
- Asynchronous code (e.g.,
setTimeout,fetch) - Server-side rendering
Creating an Error Boundary
As of React 18, Error Boundaries must be written as class components. There is no Hook equivalent yet for the core error boundary behavior — though third-party libraries like react-error-boundary provide a functional wrapper.
An error boundary class component must implement either or both of:
static getDerivedStateFromError(error)— Updates state so the next render shows a fallback UIcomponentDidCatch(error, info)— Logs the error details (e.g., to an error monitoring service)
import { Component } from 'react';
class ErrorBoundary extends Component {
constructor(props) {
super(props);
this.state = { hasError: false };
}
static getDerivedStateFromError(error) {
// Update state so the next render shows the fallback UI
return { hasError: true };
}
componentDidCatch(error, info) {
// Log the error to an error reporting service
console.error("Error caught by boundary:", error);
console.error("Component stack:", info.componentStack);
}
render() {
if (this.state.hasError) {
return <h2>Something went wrong. Please try refreshing the page.</h2>;
}
return this.props.children;
}
}
export default ErrorBoundary;
Using an Error Boundary
Wrap any component or section of the application that might throw an error:
import ErrorBoundary from './ErrorBoundary';
import UserProfile from './UserProfile';
import ProductFeed from './ProductFeed';
function App() {
return (
<div>
<ErrorBoundary>
<UserProfile />
</ErrorBoundary>
<ErrorBoundary>
<ProductFeed />
</ErrorBoundary>
</div>
);
}
If UserProfile throws an error, only that section shows the fallback message. ProductFeed continues to work normally. The rest of the application is unaffected.
Customizing the Fallback UI
A more flexible error boundary accepts a custom fallback as a prop:
class ErrorBoundary extends Component {
constructor(props) {
super(props);
this.state = { hasError: false };
}
static getDerivedStateFromError() {
return { hasError: true };
}
componentDidCatch(error, info) {
console.error(error, info);
}
render() {
if (this.state.hasError) {
return this.props.fallback || <p>Something went wrong.</p>;
}
return this.props.children;
}
}
<ErrorBoundary fallback={<div><h3>Widget unavailable</h3><p>This section failed to load.</p></div>}>
<WeatherWidget />
</ErrorBoundary>
Using react-error-boundary (Recommended for Modern Apps)
The react-error-boundary package provides a functional, modern API for error boundaries without writing class components:
npm install react-error-boundary
import { ErrorBoundary } from 'react-error-boundary';
function FallbackComponent({ error, resetErrorBoundary }) {
return (
<div>
<h3>An error occurred:</h3>
<p>{error.message}</p>
<button onClick={resetErrorBoundary}>Try Again</button>
</div>
);
}
function App() {
return (
<ErrorBoundary FallbackComponent={FallbackComponent}>
<MyComponent />
</ErrorBoundary>
);
}
The resetErrorBoundary function resets the error state and attempts to re-render the failed component — useful for "Try Again" buttons that allow users to recover from transient errors.
Strategic Placement of Error Boundaries
Placing a single error boundary at the very top of the application would catch all errors — but the entire UI would be replaced with the fallback. A better strategy is to place error boundaries around individual sections so only the broken section is affected:
- Wrap each major page or section separately
- Wrap third-party widgets or external data components individually
- Wrap each route separately when using React Router
Key Points
- Error boundaries prevent a single component error from crashing the entire application.
- They must currently be written as class components using
getDerivedStateFromErrorand/orcomponentDidCatch. - The
react-error-boundarypackage provides a modern, functional alternative. - Only errors during rendering and lifecycle methods are caught — not event handler or async errors.
- Place error boundaries around individual sections, not just at the root, for better user experience.
- Use
resetErrorBoundaryto allow users to attempt recovery after an error.
The next topic covers Higher Order Components (HOC) — a pattern for reusing component logic by wrapping components with additional behavior.
