What does Suspense do in React 18?
What Suspense is
<Suspense>is a wrapper component that lets you pause rendering part of the UI until some data (or components) are ready, and show a fallback UI instead of the "stuck" area.
In simpler terms:
Suspense= "Show a skeleton/spinner while React waits for data or a module".
The main idea
Before React 18, Suspense only worked for lazy-loading components (via React.lazy).
In React 18 it became a universal waiting mechanism:
now it can work with async data, server rendering, and streaming.
A basic usage example
import React, { Suspense, lazy } from 'react';
const Profile = lazy(() => import('./Profile'));
function App() {
return (
<Suspense fallback={<div>Loading profile...</div>}>
<Profile />
</Suspense>
);
}While the Profile component loads,
React pauses its render and shows <div>Loading profile...</div>.
Once the module loads, React "resumes" the render and inserts the ready component.
What's new in React 18
1. Suspense now works on the server (SSR)
React 18 added streaming server rendering:
- now the server can send HTML in parts,
- and Suspense lets it render the "ready chunks" right away, without waiting for the whole application to be fully assembled.
Example:
<Suspense fallback={<Skeleton />}>
<Comments />
</Suspense>If <Comments> takes longer to load, React on the server:
- sends the HTML without that block;
- shows the
Skeleton; - later "streams in" the finished HTML for the
<Comments>block; - on the client, hydration happens without jarring jumps.
New APIs for this:
renderToPipeableStream() // for Node.js
renderToReadableStream() // for Deno, Edge, etc.2. Suspense now understands async data (via libraries)
React 18 itself still can't "fetch" data, but Suspense can now wait on a Promise if a component or hook throws one. This is used in frameworks (Next.js 13+, Remix, RSC).
For example, in Next.js:
export default async function Page() {
const user = await getUser(); // an async component
return (
<Suspense fallback={<Spinner />}>
<UserInfo user={user} />
</Suspense>
);
}React automatically pauses the render until getUser() finishes,
showing a Spinner in the meantime.
3. Compatibility with Concurrent Rendering
Suspense is built on React 18's concurrent rendering.
This means React can:
- pause a component's render,
- continue rendering other parts of the UI,
- resume the render later, without blocking the interface.
That is, React literally "renders ahead" but doesn't show the component until it's ready.
4. A new level of UX
Suspense solves the problem of a "jumpy interface":
- there's no abrupt disappearance of content during loading;
- placeholders / skeletons can be shown smoothly;
Suspensecan be combined for different parts of the page (nested Suspense).
Example:
<Suspense fallback={<MainSkeleton />}>
<MainContent />
<Suspense fallback={<SidebarSkeleton />}>
<Sidebar />
</Suspense>
</Suspense>5. How React "stops" the render
The mechanics are simple:
- A Promise appears inside the component (for example, during a lazy import or a data fetch);
- React "encounters" that Promise;
- It stops rendering that part of the tree;
- It shows the
fallback; - Once the Promise resolves, React resumes the render with the real data.
6. What Suspense doesn't do on its own
- It doesn't make requests (
fetch,axios) directly, it only manages the waiting. - It doesn't handle errors (
catch), that requires an<ErrorBoundary>. - It doesn't replace
useEffect, Suspense is used during the render, not after.
Summary
<Suspense>is a declarative waiting mechanism: React pauses the render of part of the tree, shows a fallback, and then automatically resumes the render once the data or modules are ready.
In short:
| Capability | React 17 | React 18 |
|---|---|---|
| Lazy loading components | Yes | Yes |
| Waiting on data (Promise) | No | Yes |
| SSR + Streaming | No | Yes |
| Multiple levels of Suspense | Limited | Stable |
| Concurrent Rendering support | No | Yes |
Short Answer
Interview readyA concise answer to help you respond confidently on this topic during an interview.