suspense
Overview
Reference: <Suspence>
<Suspense> lets you display a fallback until its children have finished loading.
<Suspense fallback={<Loading />}>
<SomeComponent />
</Suspense>
warning
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
Why suspense?

Suspense-enabled framework (in Next.js)
- page.tsx
- Albums.tsx
- api.ts
import Albums from "@/components/Albums";
import Loading from "@/components/Loading";
import { Suspense } from "react";
export default function Home() {
return (
<main>
<Suspense fallback={<Loading />}>
<Albums />
</Suspense>
</main>
);
}
import { getAlbums } from "@/api";
// server component
export default async function Albums() {
const albums = await getAlbums();
return (
<ul>
{albums.map((album) => (
<li key={album}>{album}</li>
))}
</ul>
);
}
export const getAlbums = async () => {
await new Promise((resolve) => {
setTimeout(() => {
resolve(null);
}, 2000);
});
const res = [
"Eternal Whispers",
"Golden Horizons",
"Mystic Dreams",
"Wandering Echoes",
"Bright Shadows",
"Forgotten Tides",
"Lonely Legends",
"Silent Memories",
"Dreamy Skies",
"Lost Visions",
];
return res
};
With lazy()
- page.tsx
- Albums.tsx
import { Suspense, lazy } from "react";
import Loading from "./Loading";
import "./styles.css";
const Albums3 = lazy(() => delayForDemo(import("./Albums3.js")));
export default function App() {
const albums = getAlbums();
return (
<div className="App">
<h1>Albums by lazy</h1>
<Suspense fallback={<Loading />}>
<Albums3 albums={albums} />
</Suspense>
</div>
);
}
// Add a fixed delay so you can see the loading state
function delayForDemo(promise) {
return new Promise((resolve) => {
setTimeout(resolve, 5000);
}).then(() => promise);
}
export default function Albums3() {
const albums = [
"Eternal Whispers",
"Golden Horizons",
"Mystic Dreams",
"Wandering Echoes",
"Bright Shadows",
"Forgotten Tides",
"Lonely Legends",
"Silent Memories",
"Dreamy Skies",
"Lost Visions",
];
return (
<ul>
{albums.map((album) => (
<li>{album}</li>
))}
</ul>
);
}
Cached Promise with use
There are two ways to adopt use api:
Option 1: use cached promise
info
Since use is an api rather than hook. That's the reason we need a cached promise to avoid recreating a promise on each render.
- app.jsx
- Albums.js
- api.js
import { Suspense } from "react";
import Albums from "./Albums";
import Loading from "./Loading";
import "./styles.css";
export default function App() {
return (
<div className="App">
<h1>Albums by cached promise</h1>
<Suspense fallback={<Loading />}>
<Albums />
</Suspense>
</div>
);
}
import { use } from "react";
import { cached_getAlbums } from "./api";
export default function Albums() {
const albums = use(cached_getAlbums());
return (
<ul>
{albums.map((album) => (
<li>{album}</li>
))}
</ul>
);
}
const cache = new Map();
export const cached_getAlbums = () => {
if (!cache.get("getAlbums")) {
cache.set("getAlbums", getAlbums());
}
return cache.get("getAlbums");
};
export const getAlbums = async () => {
await new Promise((resolve) => {
setTimeout(() => {
resolve();
}, 2000);
});
return (res = [
"Eternal Whispers",
"Golden Horizons",
"Mystic Dreams",
"Wandering Echoes",
"Bright Shadows",
"Forgotten Tides",
"Lonely Legends",
"Silent Memories",
"Dreamy Skies",
"Lost Visions",
]);
};
Option 2: use promise as props
- app.jsx
- Albums2.js
- api.js
import { Suspense } from "react";
import Albums2 from "./Albums2";
import { getAlbums } from "./api";
import Loading from "./Loading";
import "./styles.css";
export default function App() {
const albums = getAlbums(); // do not await here
return (
<div className="App">
<h1>Albums by promise as props</h1>
<Suspense fallback={<Loading />}>
<Albums2 albums={albums} />
</Suspense>
</div>
);
}
import { use } from "react";
export default function Albums2({ albums }) { // albums: Promise
const _albums = use(albums);
return (
<ul>
{_albums.map((album) => (
<li>{album}</li>
))}
</ul>
);
}
export const getAlbums = async () => {
await new Promise((resolve) => {
setTimeout(() => {
resolve();
}, 2000);
});
return (res = [
"Eternal Whispers",
"Golden Horizons",
"Mystic Dreams",
"Wandering Echoes",
"Bright Shadows",
"Forgotten Tides",
"Lonely Legends",
"Silent Memories",
"Dreamy Skies",
"Lost Visions",
]);
};