Suspense - React
Suspense - React
v19
<Suspense>
<Suspense> lets you display a fallback until its children have
finished loading.
Reference
<Suspense>
Usage
Troubleshooting
Reference
https://react.dev/reference/react/Suspense 1/19
20/02/2025, 09:06 <Suspense> – React
<Suspense>
Props
Caveats
React does not preserve any state for renders that got suspended before
they were able to mount for the first time. When the component has
loaded, React will retry rendering the suspended tree from scratch.
If Suspense was displaying content for the tree, but then it suspended
again, the fallback will be shown again unless the update causing it was
caused by startTransition or useDeferredValue .
If React needs to hide the already visible content because it suspended
again, it will clean up layout Effects in the content tree. When the content
is ready to be shown again, React will fire the layout Effects again. This
ensures that Effects measuring the DOM layout don’t try to do this while
the content is hidden.
React includes under-the-hood optimizations like Streaming Server
Rendering and Selective Hydration that are integrated with Suspense.
Read an architectural overview and watch a technical talk to learn more.
Usage
You can wrap any part of your application with a Suspense boundary:
https://react.dev/reference/react/Suspense 2/19
20/02/2025, 09:06 <Suspense> – React
React will display your loading fallback until all the code and data needed by
the children has been loaded.
In the example below, the Albums component suspends while fetching the
list of albums. Until it’s ready to render, React switches the closest Suspense
boundary above to show the fallback—your Loading component. Then,
when the data loads, React hides the Loading fallback and renders the
Albums component with data.
Show more
https://react.dev/reference/react/Suspense 3/19
20/02/2025, 09:06 <Suspense> – React
Note
The exact way you would load data in the Albums component above
depends on your framework. If you use a Suspense-enabled
framework, you’ll find the details in its data fetching documentation.
By default, the whole tree inside Suspense is treated as a single unit. For
example, even if only one of these components suspends waiting for some
https://react.dev/reference/react/Suspense 4/19
20/02/2025, 09:06 <Suspense> – React
Then, after all of them are ready to be displayed, they will all appear together
at once.
In the example below, both Biography and Albums fetch some data.
However, because they are grouped under a single Suspense boundary, these
components always “pop in” together at the same time.
Show more
https://react.dev/reference/react/Suspense 5/19
20/02/2025, 09:06 <Suspense> – React
Components that load data don’t have to be direct children of the Suspense
boundary. For example, you can move Biography and Albums into a new
Details component. This doesn’t change the behavior. Biography and
Albums share the same closest parent Suspense boundary, so their reveal is
coordinated together.
https://react.dev/reference/react/Suspense 6/19
20/02/2025, 09:06 <Suspense> – React
as the next level of content becomes available. For example, you can give the
album list its own fallback:
With this change, displaying the Biography doesn’t need to “wait” for the
Albums to load.
https://react.dev/reference/react/Suspense 7/19
20/02/2025, 09:06 <Suspense> – React
Show more
Suspense boundaries let you coordinate which parts of your UI should always
“pop in” together at the same time, and which parts should progressively
reveal more content in a sequence of loading states. You can add, move, or
delete Suspense boundaries in any place in the tree without affecting the
rest of your app’s behavior.
https://react.dev/reference/react/Suspense 8/19
20/02/2025, 09:06 <Suspense> – React
Show more
https://react.dev/reference/react/Suspense 9/19
20/02/2025, 09:06 <Suspense> – React
The query will update immediately, so the input will display the new value.
However, the deferredQuery will keep its previous value until the data has
loaded, so SearchResults will show the stale results for a bit.
To make it more obvious to the user, you can add a visual indication when the
stale result list is displayed:
<div style={{
opacity: query !== deferredQuery ? 0.5 : 1
}}>
<SearchResults query={deferredQuery} />
</div>
Enter "a" in the example below, wait for the results to load, and then edit
the input to "ab" . Notice how instead of the Suspense fallback, you now see
the dimmed stale result list until the new results have loaded:
App.js Reset
https://react.dev/reference/react/Suspense 10/19
20/02/2025, 09:06 <Suspense> – React
Show more
Note
Both deferred values and Transitions let you avoid showing Suspense
fallback in favor of inline indicators. Transitions mark the whole
update as non-urgent so they are typically used by frameworks and
router libraries for navigation. Deferred values, on the other hand, are
mostly useful in application code where you want to mark a part of UI
as non-urgent and let it “lag behind” the rest of the UI.
Show more
When you pressed the button, the Router component rendered ArtistPage
instead of IndexPage . A component inside ArtistPage suspended, so the
https://react.dev/reference/react/Suspense 12/19
20/02/2025, 09:06 <Suspense> – React
To prevent this, you can mark the navigation state update as a Transition with
startTransition :
function Router() {
const [page, setPage] = useState('/');
function navigate(url) {
startTransition(() => {
setPage(url);
});
}
// ...
This tells React that the state transition is not urgent, and it’s better to keep
showing the previous page instead of hiding any already revealed content.
Now clicking the button “waits” for the Biography to load:
Show more
https://react.dev/reference/react/Suspense 13/19
20/02/2025, 09:06 <Suspense> – React
A Transition doesn’t wait for all content to load. It only waits long enough to
avoid hiding already revealed content. For example, the website Layout was
already revealed, so it would be bad to hide it behind a loading spinner.
However, the nested Suspense boundary around Albums is new, so the
Transition doesn’t wait for it.
Note
In the above example, once you click the button, there is no visual indication
that a navigation is in progress. To add an indicator, you can replace
startTransition with useTransition which gives you a boolean
isPending value. In the example below, it’s used to change the website
Show more
https://react.dev/reference/react/Suspense 15/19
20/02/2025, 09:06 <Suspense> – React
However, now imagine you’re navigating between two different user profiles.
In that case, it makes sense to show the fallback. For example, one user’s
timeline is different content from another user’s timeline. By specifying a
key , you ensure that React treats different users’ profiles as different
If you use one of the streaming server rendering APIs (or a framework that
relies on them), React will also use your <Suspense> boundaries to handle
errors on the server. If a component throws an error on the server, React will
not abort the server render. Instead, it will find the closest <Suspense>
component above it and include its fallback (such as a spinner) into the
generated server HTML. The user will see a spinner at first.
On the client, React will attempt to render the same component again. If it
errors on the client too, React will throw the error and display the closest
error boundary. However, if it does not error on the client, React will not
display the error to the user since the content was eventually displayed
successfully.
You can use this to opt out some components from rendering on the server.
To do this, throw an error in the server environment and then wrap them in a
<Suspense> boundary to replace their HTML with fallbacks:
https://react.dev/reference/react/Suspense 16/19
20/02/2025, 09:06 <Suspense> – React
function Chat() {
if (typeof window === 'undefined') {
throw Error('Chat should only render on the client.');
}
// ...
}
The server HTML will include the loading indicator. It will be replaced by the
Chat component on the client.
Troubleshooting
Replacing visible UI with a fallback creates a jarring user experience. This can
happen when an update causes a component to suspend, and the nearest
Suspense boundary is already showing content to the user.
function handleNextPageClick() {
// If this update suspends, don't hide the already displayed content
startTransition(() => {
setCurrentPage(currentPage + 1);
});
}
https://react.dev/reference/react/Suspense 17/19
20/02/2025, 09:06 <Suspense> – React
This will avoid hiding existing content. However, any newly rendered
Suspense boundaries will still immediately display fallbacks to avoid blocking
the UI and let the user see the content as it becomes available.
If your router is integrated with Suspense, it should wrap its updates into
startTransition automatically.
PREVIOUS
<StrictMode>
NEXT
APIs
uwu?
Describing the UI
Adding Interactivity
Managing State
Escape Hatches
https://react.dev/reference/react/Suspense 18/19
20/02/2025, 09:06 <Suspense> – React
Community More
Acknowledgements Terms
https://react.dev/reference/react/Suspense 19/19