is a React component that allows developers to display a fallback UI while waiting for its children to load. It provides various functionalities such as revealing content together, showing stale content, and managing transitions during navigation. The document outlines usage examples, props, caveats, and best practices for implementing _Suspense_ – React _Suspense_ – React v19 <Suspense> Reference <Suspense> Usage Troubleshooting Reference https://react.dev/reference/react/Suspense 1/19 <Suspense> Props Caveats React does not preserve any state for renders that got suspended before Usage You can wrap any part of your application with a Suspense boundary: https://react.dev/reference/react/Suspense 2/19 React will display your loading fallback until all the code and data needed by In the example below, the Albums component suspends while fetching the Show more https://react.dev/reference/react/Suspense 3/19 Note The exact way you would load data in the Albums component above By default, the whole tree inside Suspense is treated as a single unit. For Then, after all of them are ready to be displayed, they will all appear together In the example below, both Biography and Albums fetch some data. Show more https://react.dev/reference/react/Suspense 5/19 Components that load data don’t have to be direct children of the Suspense Albums share the same closest parent Suspense boundary, so their reveal is coordinated together. https://react.dev/reference/react/Suspense 6/19 as the next level of content becomes available. For example, you can give the With this change, displaying the Biography doesn’t need to “wait” for the https://react.dev/reference/react/Suspense 7/19 Show more Suspense boundaries let you coordinate which parts of your UI should always https://react.dev/reference/react/Suspense 8/19 Show more https://react.dev/reference/react/Suspense 9/19 The query will update immediately, so the input will display the new value. To make it more obvious to the user, you can add a visual indication when the <div style={{ Enter "a" in the example below, wait for the results to load, and then edit App.js Reset https://react.dev/reference/react/Suspense 10/19 Show more Note Both deferred values and Transitions let you avoid showing Suspense Show more When you pressed the button, the Router component rendered ArtistPage https://react.dev/reference/react/Suspense 12/19 To prevent this, you can mark the navigation state update as a Transition with function Router() { function navigate(url) { This tells React that the state transition is not urgent, and it’s better to keep Show more https://react.dev/reference/react/Suspense 13/19 A Transition doesn’t wait for all content to load. It only waits long enough to Note In the above example, once you click the button, there is no visual indication Show more https://react.dev/reference/react/Suspense 15/19 However, now imagine you’re navigating between two different user profiles. If you use one of the streaming server rendering APIs (or a framework that On the client, React will attempt to render the same component again. If it You can use this to opt out some components from rendering on the server. https://react.dev/reference/react/Suspense 16/19 function Chat() { The server HTML will include the loading indicator. It will be replaced by the Troubleshooting Replacing visible UI with a fallback creates a jarring user experience. This can function handleNextPageClick() { https://react.dev/reference/react/Suspense 17/19 This will avoid hiding existing content. However, any newly rendered 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 PREVIOUS <StrictMode> NEXT APIs uwu? Describing the UI Adding Interactivity Managing State Escape Hatches https://react.dev/reference/react/Suspense 18/19 Community More Acknowledgements Terms https://react.dev/reference/react/Suspense 19/19Uploaded by
dungeon.dad87Uploaded by
dungeon.dad8720/02/2025, 09:06 <Suspense> – React
API REFERENCE COMPONENTS
<Suspense> lets you display a fallback until its children have
finished loading. <Suspense fallback={<Loading />}>
<SomeComponent />
</Suspense> Displaying a fallback while content is loading
Revealing content together at once
Revealing nested content as it loads
Showing stale content while fresh content is loading
Preventing already revealed content from hiding
Indicating that a Transition is happening
Resetting Suspense boundaries on navigation
Providing a fallback for server errors and client-only content How do I prevent the UI from being replaced by a fallback during an
update?
20/02/2025, 09:06 <Suspense> – React children : The actual UI you intend to render. If children suspends while
rendering, the Suspense boundary will switch to rendering fallback .
fallback : An alternate UI to render in place of the actual UI if it has not
finished loading. Any valid React node is accepted, though in practice, a
fallback is a lightweight placeholder view, such as a loading spinner or
skeleton. Suspense will automatically switch to fallback when
children suspends, and back to children when the data is ready. If
fallback suspends while rendering, it will activate the closest parent
Suspense boundary.
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. Displaying a fallback while content is loading
20/02/2025, 09:06 <Suspense> – React <Suspense fallback={ <Loading /> }>
<Albums />
</Suspense>
the children has been loaded.
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. ArtistPage.js Albums.js Reset
import { Suspense } from 'react';
import Albums from './Albums.js'; export default function ArtistPage({ artist }) {
return (
<>
<h1>{artist.name}</h1>
<Suspense fallback={<Loading />}>
<Albums artistId={artist.id} />
</Suspense>
</>
);
20/02/2025, 09:06 <Suspense> – React Only Suspense-enabled data sources will activate the Suspense
component. They include: Data fetching with Suspense-enabled frameworks like Relay and
Next.js
Lazy-loading component code with lazy
Reading the value of a cached Promise with use Suspense does not detect when data is fetched inside an Effect or
event handler.
depends on your framework. If you use a Suspense-enabled
framework, you’ll find the details in its data fetching documentation. Suspense-enabled data fetching without the use of an opinionated
framework is not yet supported. The requirements for implementing
a Suspense-enabled data source are unstable and undocumented.
An official API for integrating data sources with Suspense will be
released in a future version of React. Revealing content together at once
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 data, all of them together will be replaced by the loading indicator:
<Suspense fallback={<Loading />}>
<Biography />
<Panel>
<Albums />
</Panel>
</Suspense>
at once.
However, because they are grouped under a single Suspense boundary, these
components always “pop in” together at the same time. ArtistPage.js Panel.js Biography.js Albums.js Reset
import { Suspense } from 'react';
import Albums from './Albums.js';
import Biography from './Biography.js';
import Panel from './Panel.js'; export default function ArtistPage({ artist }) {
return (
<>
<h1>{artist.name}</h1>
<Suspense fallback={<Loading />}>
<Biography artistId={artist.id} />
<Panel>
20/02/2025, 09:06 <Suspense> – React
boundary. For example, you can move Biography and Albums into a new
Details component. This doesn’t change the behavior. Biography and <Suspense fallback={<Loading />}>
<Details artistId={artist.id} />
</Suspense> function Details({ artistId }) {
return (
<>
<Biography artistId={artistId} />
<Panel>
<Albums artistId={artistId} />
</Panel>
</>
);
} Revealing nested content as it loads
When a component suspends, the closest parent Suspense component
shows the fallback. This lets you nest multiple Suspense components to
create a loading sequence. Each Suspense boundary’s fallback will be filled in
20/02/2025, 09:06 <Suspense> – React
album list its own fallback: <Suspense fallback={<BigSpinner />}>
<Biography />
<Suspense fallback={<AlbumsGlimmer />}>
<Panel>
<Albums />
</Panel>
</Suspense>
</Suspense>
Albums to load. The sequence will be:
1. If Biography hasn’t loaded yet, BigSpinner is shown in place of the
entire content area.
2. Once Biography finishes loading, BigSpinner is replaced by the content.
3. If Albums hasn’t loaded yet, AlbumsGlimmer is shown in place of Albums
and its parent Panel .
4. Finally, once Albums finishes loading, it replaces AlbumsGlimmer . ArtistPage.js Panel.js Biography.js Albums.js Reset
import { Suspense } from 'react';
import Albums from './Albums.js';
import Biography from './Biography.js';
import Panel from './Panel.js'; export default function ArtistPage({ artist }) {
return (
<>
<h1>{artist.name}</h1>
<Suspense fallback={<BigSpinner />}>
<Biography artistId={artist.id} />
<Suspense fallback={<AlbumsGlimmer />}>
20/02/2025, 09:06 <Suspense> – React
“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. Don’t put a Suspense boundary around every component. Suspense
boundaries should not be more granular than the loading sequence that you
want the user to experience. If you work with a designer, ask them where the
loading states should be placed—it’s likely that they’ve already included
them in their design wireframes. Showing stale content while fresh content is loading
In this example, the SearchResults component suspends while fetching the
search results. Type "a" , wait for the results, and then edit it to "ab" . The
results for "a" will get replaced by the loading fallback.
20/02/2025, 09:06 <Suspense> – React App.js SearchResults.js Reset
import { Suspense, useState } from 'react';
import SearchResults from './SearchResults.js'; export default function App() {
const [query, setQuery] = useState('');
return (
<>
<label>
Search albums:
<input value={query} onChange={e => setQuery(e.target.value)}
</label> A common alternative UI pattern is to defer updating the list and to keep
showing the previous results until the new results are ready. The
useDeferredValue Hook lets you pass a deferred version of the query down: export default function App() {
const [query, setQuery] = useState('');
20/02/2025, 09:06 <Suspense> – React const deferredQuery = useDeferredValue(query);
return (
<>
<label>
Search albums:
<input value={query} onChange={e => setQuery(e.target.value)} />
</label>
<Suspense fallback={<h2>Loading...</h2>}>
<SearchResults query={deferredQuery} />
</Suspense>
</>
);
}
However, the deferredQuery will keep its previous value until the data has
loaded, so SearchResults will show the stale results for a bit.
stale result list is displayed:
opacity: query !== deferredQuery ? 0.5 : 1
}}>
<SearchResults query={deferredQuery} />
</div>
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: import { Suspense, useState, useDeferredValue } from 'react';
import SearchResults from './SearchResults.js'; export default function App() {
const [query, setQuery] = useState('');
20/02/2025, 09:06 <Suspense> – React const deferredQuery = useDeferredValue(query);
const isStale = query !== deferredQuery;
return (
<>
<label>
S h lb
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. Preventing already revealed content from hiding
https://react.dev/reference/react/Suspense 11/19
20/02/2025, 09:06 <Suspense> – React When a component suspends, the closest parent Suspense boundary
switches to showing the fallback. This can lead to a jarring user experience if
it was already displaying some content. Try pressing this button: App.js Layout.js IndexPage.js ArtistPage.js Albums.js Reset
import { Suspense, useState } from 'react';
import IndexPage from './IndexPage.js';
import ArtistPage from './ArtistPage.js';
import Layout from './Layout.js'; export default function App() {
return (
<Suspense fallback={<BigSpinner />}>
<Router />
</Suspense>
);
}
instead of IndexPage . A component inside ArtistPage suspended, so the
20/02/2025, 09:06 <Suspense> – React closest Suspense boundary started showing the fallback. The closest
Suspense boundary was near the root, so the whole site layout got replaced
by BigSpinner .
startTransition :
const [page, setPage] = useState('/');
startTransition(() => {
setPage(url);
});
}
// ...
showing the previous page instead of hiding any already revealed content.
Now clicking the button “waits” for the Biography to load: App.js Layout.js IndexPage.js ArtistPage.js Albums.js Reset
import { Suspense, startTransition, useState } from 'react';
import IndexPage from './IndexPage.js';
import ArtistPage from './ArtistPage.js';
import Layout from './Layout.js'; export default function App() {
return (
<Suspense fallback={<BigSpinner />}>
<Router />
</Suspense>
);
}
20/02/2025, 09:06 <Suspense> – React
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. Suspense-enabled routers are expected to wrap the navigation
updates into Transitions by default. Indicating that a Transition is happening
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 header styling while a Transition is happening:
https://react.dev/reference/react/Suspense 14/19
20/02/2025, 09:06 <Suspense> – React App.js Layout.js IndexPage.js ArtistPage.js Albums.js Reset
import { Suspense, useState, useTransition } from 'react';
import IndexPage from './IndexPage.js';
import ArtistPage from './ArtistPage.js';
import Layout from './Layout.js'; export default function App() {
return (
<Suspense fallback={<BigSpinner />}>
<Router />
</Suspense>
);
} Resetting Suspense boundaries on navigation
During a Transition, React will avoid hiding already revealed content.
However, if you navigate to a route with different parameters, you might
want to tell React it is different content. You can express this with a key :
20/02/2025, 09:06 <Suspense> – React <ProfilePage key={queryParams.id} />
Imagine you’re navigating within a user’s profile page, and something
suspends. If that update is wrapped in a Transition, it will not trigger the
fallback for already visible content. That’s the expected behavior.
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 components, and resets the Suspense boundaries during navigation.
Suspense-integrated routers should do this automatically. Providing a fallback for server errors and client-only
content
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.
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.
To do this, throw an error in the server environment and then wrap them in a
<Suspense> boundary to replace their HTML with fallbacks:
20/02/2025, 09:06 <Suspense> – React <Suspense fallback={<Loading />}>
<Chat />
</Suspense>
if (typeof window === 'undefined') {
throw Error('Chat should only render on the client.');
}
// ...
}
Chat component on the client. How do I prevent the UI from being replaced by a
fallback during an update?
happen when an update causes a component to suspend, and the nearest
Suspense boundary is already showing content to the user. To prevent this from happening, mark the update as non-urgent using
startTransition . During a Transition, React will wait until enough data has
loaded to prevent an unwanted fallback from appearing:
// If this update suspends, don't hide the already displayed content
startTransition(() => {
setCurrentPage(currentPage + 1);
});
}
20/02/2025, 09:06 <Suspense> – React
Suspense boundaries will still immediately display fallbacks to avoid blocking React will only prevent unwanted fallbacks during non-urgent updates. It
will not delay a render if it’s the result of an urgent update. You must opt in
with an API like startTransition or useDeferredValue .
startTransition automatically. Copyright © Meta Platforms, Inc
Learn React API Reference
Quick Start React APIs
Installation React DOM APIs
20/02/2025, 09:06 <Suspense> – React Code of Conduct Blog
Meet the Team React Native
Docs Contributors Privacy
You might also like