React: From Components to Production · Fetching and Caching Server Data

Suspense and Error Boundaries

Declare loading and error UI around parts of the tree.

Suspense shows a fallback while children are waiting for code (lazy) or data from Suspense-enabled sources (useSuspenseQuery, framework loaders, React 19's use(promise)). Error boundaries catch rendering errors in their subtree and show fallback UI; use react-error-boundary for a function-component API. Place boundaries to keep failures and loading states local, not app-wide.

import { Suspense } from "react";
import { ErrorBoundary } from "react-error-boundary";
import { useSuspenseQuery, QueryErrorResetBoundary } from "@tanstack/react-query";

function Profile({ id }: { id: string }) {
  const { data } = useSuspenseQuery({ queryKey: ["user", id], queryFn: () => fetchUser(id) });
  return <h2>{data.name}</h2>;   // data is always defined here
}

export function ProfileSection({ id }: { id: string }) {
  return (
    <QueryErrorResetBoundary>
      {({ reset }) => (
        <ErrorBoundary onReset={reset} fallbackRender={({ resetErrorBoundary }) => (
          <div role="alert">Couldn't load profile <button onClick={resetErrorBoundary}>Retry</button></div>
        )}>
          <Suspense fallback={<ProfileSkeleton />}>
            <Profile id={id} />
          </Suspense>
        </ErrorBoundary>
      )}
    </QueryErrorResetBoundary>
  );
}

Common pitfalls

  • One Suspense boundary at the root, so any loading hides the entire page.
  • Expecting error boundaries to catch errors in event handlers or async code (they don't).
  • Waterfalls: sequential suspending children that could load in parallel.

Key points

  • Suspense handles loading declaratively
  • Error boundaries catch render errors
  • Place boundaries close to the data

Further reading: react.dev: Suspense

Practice questions

Which errors do error boundaries NOT catch?

Answer

Errors in event handlers, asynchronous code (setTimeout, promises outside rendering), server-side rendering, and errors thrown in the boundary itself.

What is a request waterfall with Suspense?

Answer

When a component suspends, its children don't render until it resolves, so their data requests start only afterwards. Start fetches in parallel (prefetch in loaders or a parent) to avoid it.

Open in the app to mark lessons complete, take notes and track your progress.