Suspense
Suspense
<Suspense> is a built-in React component that lets you “suspend” the rendering of a component tree until some condition is met (usually waiting for data or code to load). While it waits, it displays a fallback UI.
How Suspense Works
Traditionally, React renders synchronously. It starts at the top of the tree and renders every component until it hits the bottom.
Suspense introduces the concept of a component “throwing a promise” during render. If a component throws a promise, React stops rendering that branch of the tree. It looks up the tree for the nearest <Suspense> boundary, and renders its fallback prop instead. Once the promise resolves, React tries to render the component again.
Primary Use Cases
1. Code Splitting (React.lazy)
The most common use of Suspense in standard React apps is catching the loading state of components imported via React.lazy.
import { lazy, Suspense } from 'react';
// The browser starts downloading this file...
const HeavyComponent = lazy(() => import('./HeavyComponent'));
function App() {
return (
<div>
{/* ... and Suspense shows this until the download finishes */}
<Suspense fallback={<LoadingSpinner />}>
<HeavyComponent />
</Suspense>
</div>
);
}
2. Data Fetching (React Server Components / Frameworks)
In modern React architectures (like Next.js App Router, Remix, or Relay), Suspense is used for declarative data fetching. Instead of manually tracking isLoading state in every component, you just read the data. If the data isn’t there yet, the framework suspends the component.
// Example in a Suspense-enabled framework
function UserProfile({ userId }) {
// readData will throw a Promise if the data is not yet cached
const user = readData(`/api/users/${userId}`);
return <h1>{user.name}</h1>;
}
function App() {
return (
<Suspense fallback={<SkeletonProfile />}>
<UserProfile userId={123} />
</Suspense>
);
}
Nesting Suspense Boundaries
You can place multiple <Suspense> components at different levels of your application to create granular loading states.
React will always use the nearest boundary above the suspending component.
function Dashboard() {
return (
// If Sidebar or MainContent suspends, the whole page shows a big spinner
<Suspense fallback={<BigPageSpinner />}>
<Layout>
<Sidebar />
{/* If UserFeed suspends, ONLY this area shows a skeleton,
the Sidebar remains visible! */}
<Suspense fallback={<FeedSkeleton />}>
<UserFeed />
</Suspense>
</Layout>
</Suspense>
);
}
Suspense vs. Error Boundaries
Suspense handles the “loading” state. It does not handle the “error” state (e.g., if the network request for the lazy component fails).
To handle errors, you must wrap your <Suspense> component in an Error Boundary.
<ErrorBoundary fallback={<ErrorMessage />}>
<Suspense fallback={<Spinner />}>
<LazyComponent />
</Suspense>
</ErrorBoundary>
Interview Questions
Q: What is the purpose of React <Suspense>?
A: It allows you to specify a declarative fallback UI (like a loading spinner or skeleton screen) to display while components deeper in the tree are waiting for some asynchronous operation to finish (like lazy-loading a code chunk or fetching data).