Useful Cheatsheetsusefulcheatsheets.com
React Suspense
Chapter 18 · Page 126
Intermediate

React Suspense

Load components and data with Suspense boundaries for better UX and streaming.

TL;DR

  1. 01Use Suspense to show loading states while components or data load.
  2. 02Wrap lazy-loaded components in Suspense for fallback UI.
  3. 03Combine with error boundaries for complete async error handling.

Tips

  1. 01Nest Suspense boundaries at different levels to show partial content incrementally while the rest loads.

Warnings

  1. 01Suspense for data fetching is still experimental in React 19 — check version compatibility and use established libraries like React Query for production apps.
Notes
Useful Cheatsheetsusefulcheatsheets.com
React Suspense
Chapter 18 · Page 127
Intermediate

React Suspense

(continued)

Suspense Basics

  • Wrap Suspense around components that may suspend.
    import { Suspense, lazy } from "react";
    
    const HeavyComponent = lazy(() => import("./HeavyComponent"));
    
    export default function App() {
      return (
        <Suspense fallback={<p>Loading...</p>}>
          <HeavyComponent />
        </Suspense>
      );
    }
  • The fallback prop shows while the component is loading.
  • Once loaded, the component replaces the fallback.
  • Suspense can wrap multiple components at once.
    <Suspense fallback={<div>Loading page...</div>}>
      <Header />
      <MainContent />
      <Sidebar />
    </Suspense>
  • Use a skeleton or spinner as the fallback for a better UX.
    <Suspense fallback={<PageSkeleton />}>
      <Dashboard />
    </Suspense>
Notes
Useful Cheatsheetsusefulcheatsheets.com
React Suspense
Chapter 18 · Page 128
Intermediate

React Suspense

(continued)

Code Splitting with Suspense

  • Use lazy to split code and load components on demand.
    const Dashboard = lazy(() => import("./pages/Dashboard"));
    const Settings = lazy(() => import("./pages/Settings"));
    
    export default function App({ page }) {
      return (
        <Suspense fallback={<p>Loading page...</p>}>
          {page === "dashboard" && <Dashboard />}
          {page === "settings" && <Settings />}
        </Suspense>
      );
    }
  • Each lazy component is a separate code chunk.
  • Chunks load only when the component is about to render.
  • Significantly reduces initial bundle size for large apps.
  • Combine with React Router for route-based code splitting.
    const Home = lazy(() => import("./pages/Home"));
    const Profile = lazy(() => import("./pages/Profile"));
    
    <Suspense fallback={<p>Loading...</p>}>
      <Routes>
        <Route path="/" element={<Home />} />
        <Route path="/profile" element={<Profile />} />
      </Routes>
    </Suspense>
Notes
Useful Cheatsheetsusefulcheatsheets.com
React Suspense
Chapter 18 · Page 129
Intermediate

React Suspense

(continued)

Data Fetching with Suspense

  • Use React Query or SWR with Suspense for data fetching.
    function UserProfile({ userId }) {
      const { data: user } = useSuspenseQuery({
        queryKey: ["user", userId],
        queryFn: () => fetchUser(userId)
      });
      
      return <div>{user.name}</div>;
    }
    
    <Suspense fallback={<p>Loading user...</p>}>
      <UserProfile userId={1} />
    </Suspense>
  • Suspense handles loading states automatically.
  • No need for manual loading state management.
  • Error boundaries catch fetch errors thrown outside Suspense.
  • Wrap the data-fetching component, not the calling component.
    // UserProfile suspends internally — wrap it here
    function Page() {
      return (
        <Suspense fallback={<Spinner />}>
          <UserProfile userId={userId} />
        </Suspense>
      );
    }
Notes
Useful Cheatsheetsusefulcheatsheets.com
React Suspense
Chapter 18 · Page 130
Intermediate

React Suspense

(continued)

Nested Suspense Boundaries

  • Use multiple Suspense boundaries for granular control.
    <Suspense fallback={<p>Loading page...</p>}>
      <Header />
      <Suspense fallback={<p>Loading content...</p>}>
        <MainContent />
      </Suspense>
      <Suspense fallback={<p>Loading sidebar...</p>}>
        <Sidebar />
      </Suspense>
    </Suspense>
  • Each boundary can have its own fallback UI.
  • Inner boundaries resolve independently of each other.
  • Outer fallback shows only for outer-level suspensions.
  • Great for showing partial content while loading.
  • Place boundaries close to each suspending component for best UX.
    // Narrow boundary: only hides the part that's loading
    function ProductList() {
      return (
        <ul>
          {productIds.map(id => (
            <Suspense key={id} fallback={<li>Loading...</li>}>
              <ProductItem id={id} />
            </Suspense>
          ))}
        </ul>
      );
    }
Notes
Useful Cheatsheetsusefulcheatsheets.com
React Suspense
Chapter 18 · Page 131
Intermediate

React Suspense

(continued)

Advanced Patterns

  • Combine Suspense with Error Boundaries.
    <ErrorBoundary fallback={<p>Error loading page</p>}>
      <Suspense fallback={<p>Loading...</p>}>
        <PageContent />
      </Suspense>
    </ErrorBoundary>
  • Transition to new content with useTransition.
    function App() {
      const [isPending, startTransition] = useTransition();
      const [page, setPage] = useState("home");
      
      const navigate = (newPage) => {
        startTransition(() => setPage(newPage));
      };
      
      return (
        <Suspense fallback={<p>Loading...</p>}>
          {isPending && <p>Loading new page...</p>}
          <PageContent page={page} />
        </Suspense>
      );
    }
  • Use startTransition to keep the old UI visible while new content loads.
  • Preload lazy components early to avoid loading delays.
    // Preload on hover before user clicks
    const LazyPage = lazy(() => import("./Page"));
    
    function NavLink({ href, children }) {
      return (
        <a href={href} onMouseEnter={() => import("./Page")}>
          {children}
        </a>
      );
    }
  • Use the react-error-boundary package for ready-made Error Boundaries.
    import { ErrorBoundary } from "react-error-boundary";
    
    <ErrorBoundary fallbackRender={({ error }) => <p>Error: {error.message}</p>}>
      <Suspense fallback={<Spinner />}>
        <AsyncComponent />
      </Suspense>
    </ErrorBoundary>
Notes
Useful Cheatsheetsusefulcheatsheets.com
React Suspense
Chapter 18 · Page 132
Intermediate

React Suspense

(FAQ)

FAQ

Suspense for data fetching is experimental in React 19 and not recommended for production without a supporting library. Use React Query or SWR instead — they integrate with Suspense via their own stable APIs and handle caching, retries, and deduplication.

Wrap React.lazy(() => import('./MyComponent')) in a Suspense boundary with a fallback prop: <Suspense fallback={}>. The fallback renders until the dynamic import resolves, so keep it lightweight to avoid layout shift.

All siblings suspend together — the single fallback shows until every component in the boundary is ready. To show components progressively as they load, wrap each in its own Suspense boundary so resolved components render immediately without waiting for slower siblings.

Suspense handles the loading state but not errors — a thrown promise triggers the fallback, while a thrown error propagates up to the nearest error boundary. Always pair Suspense with an ErrorBoundary component wrapping it to catch fetch failures or import errors.

Yes — Next.js App Router uses React's streaming SSR with Suspense, sending HTML in chunks as each boundary resolves on the server. Wrap async Server Components in Suspense to stream partial content to the client rather than blocking the entire page render.