Advanced⏱️ 9 min📘 Topic 12 of 13

🛟 React Error Boundaries and Suspense — Graceful Failures & Loading

Master React Error Boundaries and Suspense. Catch component errors, show fallback UI, lazy-load routes and handle async with React's built-in primitives.

Production apps need to fail well: render a fallback instead of a blank white screen, and show loading states without manual if (loading) chains.

🛡️ Error Boundaries

A component that catches errors thrown by its descendants during render. Today, they're still class components only (functional version is on the roadmap).

class ErrorBoundary extends React.Component {
  state = { error: null };
  static getDerivedStateFromError(error) { return { error }; }
  componentDidCatch(error, info) {
    sendToSentry(error, info);
  }
  render() {
    if (this.state.error) return <Fallback err={this.state.error} />;
    return this.props.children;
  }
}

⚠️ What boundaries DO catch

  • Render errors
  • Lifecycle errors
  • Errors in child constructors

🚫 What they DON'T catch

  • Event handlers (wrap in try/catch)
  • setTimeout / async code
  • Server-side rendering errors
  • Errors thrown in the boundary itself

⏳ Suspense

Declarative loading boundary. Wrap an async or lazy-loaded component; show a fallback while it loads.

const Profile = React.lazy(() => import('./Profile'));

<Suspense fallback={<Spinner />}>
  <Profile />
</Suspense>

💡 The combo

Wrap a Suspense with an ErrorBoundary: success → render, loading → spinner, error → fallback. Clean, declarative.

💻 Code Examples

Lazy-loading a route

const Dashboard = React.lazy(() => import('./Dashboard'));

function App() {
  return (
    <Suspense fallback={<Spinner />}>
      <Routes>
        <Route path="/dash" element={<Dashboard />} />
      </Routes>
    </Suspense>
  );
}
Output:
Dashboard's JS chunk is fetched only when the user navigates to /dash.

Boundary around a feature

<ErrorBoundary fallback={<p>Comments failed to load.</p>}>
  <Comments postId={id} />
</ErrorBoundary>
Output:
If Comments throws during render, only that section degrades — the rest of the page still works.

⚠️ Common Mistakes

  • Putting one giant boundary around the whole app — any error blanks the whole page. Place smaller boundaries around independent features.
  • Expecting boundaries to catch async errors — they don't. Use try/catch + state, or rely on libs like React Query.
  • Forgetting Suspense around lazy components — React throws if it suspends without a boundary above.
  • Logging errors only to console — wire to Sentry/LogRocket/etc. in componentDidCatch.

🎯 Interview Questions

Real questions asked at top product and service-based companies.

Q1.What is a React Error Boundary?Intermediate
A component that uses getDerivedStateFromError and componentDidCatch to catch errors thrown by descendants during render, in lifecycle methods, and in child constructors. It renders a fallback UI instead of crashing the whole tree.
Q2.What errors do Error Boundaries NOT catch?Intermediate
Event handlers (use try/catch), async code (setTimeout/Promises), SSR errors, and errors thrown in the boundary itself. They only catch errors during the render phase of the children.
Q3.What is React.lazy and why use it?Intermediate
React.lazy lets you dynamically import a component as a separate JS chunk. Combined with Suspense, the chunk loads only when the component renders — shrinking the initial bundle and speeding up the first load.
Q4.What does Suspense do?Intermediate
Declares a loading boundary. Any descendant that throws a Promise (lazy components, libraries that suspend like React Query in suspense mode) shows the Suspense `fallback` UI until the Promise resolves.
Q5.Can you write an Error Boundary as a functional component?Advanced
Not yet — there's no hook equivalent of componentDidCatch. The common practice is to write one class boundary (or use react-error-boundary library) and reuse it everywhere.

🧠 Quick Summary

  • Error Boundaries catch render errors — show fallback instead of blank screen.
  • Currently class-only; react-error-boundary is the popular wrapper.
  • They don't catch async, event-handler, or SSR errors.
  • Suspense + React.lazy = declarative loading + code splitting.
  • Combine boundaries with Suspense for success/loading/error states.