Skip to main content

React Error Boundaries

What Are Error Boundaries?

Error Boundaries are class components that catch JavaScript errors in child components during rendering, lifecycle methods, and constructors — displaying fallback UI instead of crashing the app.

Two lifecycle methods:

  • static getDerivedStateFromError(error) — update state during render phase (pure, no side effects)
  • componentDidCatch(error, info) — log errors during commit phase (allows side effects)

Basic Implementation

class ErrorBoundary extends React.Component {
state = { hasError: false, error: null };

static getDerivedStateFromError(error) {
return { hasError: true, error };
}

componentDidCatch(error, info) {
// Log to error monitoring service
errorMonitoring.report(error, {
componentStack: info.componentStack,
userId: getCurrentUser()?.id
});
}

render() {
if (this.state.hasError) {
return (
<div role="alert">
<h2>Something went wrong</h2>
<p>{this.state.error.message}</p>
<button onClick={() => this.setState({ hasError: false, error: null })}>
Try again
</button>
</div>
);
}
return this.props.children;
}
}

What Error Boundaries DON'T Catch

  • Event handlers — use try/catch instead
  • Async code — setTimeout, Promises
  • SSR errors
  • Errors in the boundary itself

Strategic Placement

// 1. Root-level: catch catastrophic failures
function App() {
return (
<ErrorBoundary fallback={<CrashPage />}>
<Router />
</ErrorBoundary>
);
}

// 2. Route-level: isolate pages from each other
function Router() {
return (
<Routes>
<Route path="/dashboard" element={
<ErrorBoundary fallback={<PageError />}>
<Dashboard />
</ErrorBoundary>
} />
</Routes>
);
}

// 3. Feature-level: graceful degradation
function ProductPage() {
return (
<div>
<ProductDetails /> {/* Critical */}
<ErrorBoundary fallback={<p>Reviews unavailable</p>}>
<ReviewSection /> {/* Non-critical */}
</ErrorBoundary>
</div>
);
}

React 18 + Suspense Integration

<ErrorBoundary fallback={<ErrorUI />}>
<Suspense fallback={<Loading />}>
<AsyncComponent />
</Suspense>
</ErrorBoundary>

This handles three states:

  • Loading — Suspense shows skeleton
  • Error — ErrorBoundary shows error UI
  • Success — component renders

Streaming SSR

With React 18's streaming SSR, errors in one component don't break the entire stream:

// Server renders partial page even if one section errors
<ErrorBoundary fallback={<SectionError />}>
<Suspense fallback={<Skeleton />}>
<SlowDataSection /> {/* Can error without breaking other sections */}
</Suspense>
</ErrorBoundary>

Auto-Reset on Navigation

function RouteErrorBoundary({ children }) {
const location = useLocation();

return (
<ErrorBoundary
key={location.pathname} // New key = resets error state on navigation
fallback={<PageError />}
>
{children}
</ErrorBoundary>
);
}

Using react-error-boundary Library

import { ErrorBoundary } from 'react-error-boundary';

function ErrorFallback({ error, resetErrorBoundary }) {
return (
<div>
<p>Error: {error.message}</p>
<button onClick={resetErrorBoundary}>Try again</button>
</div>
);
}

<ErrorBoundary
FallbackComponent={ErrorFallback}
onError={(error, info) => logError(error, info)}
onReset={() => window.location.reload()}
>
<Dashboard />
</ErrorBoundary>

Content from Frontend-Master-Prep-Series03-react