React Error Boundaries: a practical guide to resilient component trees
← Back
April 4, 2026React6 min read

React Error Boundaries: a practical guide to resilient component trees

Published April 4, 20266 min read

I was using a third-party chart library when it threw an uncaught exception on unusual data. The whole React app unmounted. A blank white screen. Every user on that page saw nothing. If I had placed an error boundary around that chart component, only the chart would have shown an error state — the rest of the page would have kept working. Error boundaries are one of the most underused resilience tools in React.

The reusable ErrorBoundary component

React does not ship a ready-to-use ErrorBoundary class. Install the community package or write your own:

bash
npm install react-error-boundary
typescript
import { ErrorBoundary } from 'react-error-boundary';

function FallbackComponent({
  error,
  resetErrorBoundary,
}: {
  error: Error;
  resetErrorBoundary: () => void;
}) {
  return (
    

Something went wrong

Error details
{error.message}
); } // Wrap any component that might throw export function DashboardChart({ data }: { data: unknown }) { return ( ); }

Placement strategy: granular vs coarse

Where you place error boundaries determines how much of your UI survives a failure:

typescript
// Coarse: one boundary protects the whole page
// A single widget failure kills the whole page content
export default function DashboardPage() {
  return (
    
      
    
  );
}

// Granular: each section is isolated
// Recommended for dashboards with independent sections
export default function DashboardPage() {
  return (
    
); }

Error reporting inside boundaries

typescript
import * as Sentry from '@sentry/react';

function ReportingErrorBoundary({
  children,
  section,
}: {
  children: React.ReactNode;
  section: string;
}) {
  return (
     (
        

This section failed to load

)} onError={(error, info) => { // Report to your error tracking service Sentry.captureException(error, { extra: { section, componentStack: info.componentStack, }, }); console.error(`Error in ${section}:`, error); }} > {children}
); }

The reset key pattern

When your data changes (e.g., the user navigates to a different item), you want to reset the error boundary. The resetKeys prop watches values and resets when they change:

typescript
function ProductDetail({ productId }: { productId: string }) {
  return (
    
      
    
  );
}

Async errors are NOT caught by boundaries

Error boundaries only catch synchronous render errors and errors in lifecycle methods. They do NOT catch:

  • Async errors in event handlers
  • Errors in setTimeout/setInterval callbacks
  • Errors in server-side rendering
typescript
// This is NOT caught by an error boundary
async function handleClick() {
  const data = await fetchData(); // If this throws, it won't hit the boundary
}

// To make async errors catchable, convert to state:
function Component() {
  const [error, setError] = useState(null);
  
  if (error) throw error; // Re-throw synchronously so boundary catches it
  
  async function handleClick() {
    try {
      await fetchData();
    } catch (err) {
      setError(err as Error); // Triggers re-render, throws synchronously above
    }
  }
}

Error boundaries are not a way to handle expected errors — use try/catch for those. They are a last-resort safety net for unexpected component failures. Every significant UI section in a production app should have one.

Share this
← All Posts6 min read