Skip to content

Commit 2942718

Browse files
committed
Enhance Suspense documentation with additional details on font and image loading during <ViewTransition> updates
1 parent d56099a commit 2942718

1 file changed

Lines changed: 22 additions & 24 deletions

File tree

src/content/reference/react/Suspense.md

Lines changed: 22 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,8 @@ A Suspense boundary waits for its content to be ready before revealing it. Any o
4646
- Reading a Promise with [`use`](/reference/react/use), including data streamed from [Server Components](/reference/rsc/server-components) or loaded through a [Suspense-enabled framework](#suspense-enabled-frameworks).
4747
- Loading a stylesheet rendered with [`<link rel="stylesheet">` and a `precedence` prop.](/reference/react-dom/components/link#special-rendering-behavior) React blocks the boundary until the stylesheet loads, up to a timeout. [See an example below.](#waiting-for-a-stylesheet-to-load)
4848
- Waiting for a large boundary's HTML to arrive during streaming server rendering. Sending HTML takes time, so a boundary with enough content activates even when nothing in it suspends. React reveals the content as the HTML arrives.
49-
- Loading fonts. This doesn't happen by default, but a [`<ViewTransition>`](/reference/react/ViewTransition) update waits for new fonts to load, up to a timeout, so text doesn't flash with a fallback font. [See an example below.](#waiting-for-a-font-to-load)
50-
- Loading images. This doesn't happen by default, but during a [`<ViewTransition>`](/reference/react/ViewTransition) update, an image's `src` blocks the boundary until the image loads, up to a timeout. Adding an `onLoad` handler opts a specific image out. [See an example below.](#waiting-for-an-image-to-load)
49+
- <CanaryBadge /> Loading fonts. Suspense doesn't wait for fonts by default, but a [`<ViewTransition>`](/reference/react/ViewTransition) update waits for new fonts to load, up to a timeout, so text doesn't flash with a fallback font. [See an example below.](#waiting-for-a-font-to-load)
50+
- <CanaryBadge /> Loading images. Suspense doesn't wait for images by default, but during a [`<ViewTransition>`](/reference/react/ViewTransition) update, React blocks the boundary until the image loads, up to a timeout. Adding an `onLoad` handler opts a specific image out. [See an example below.](#waiting-for-an-image-to-load)
5151
- <ExperimentalBadge /> Performing CPU-bound render work inside a `<Suspense>` boundary marked with the `defer` prop.
5252

5353
<Note>
@@ -437,7 +437,7 @@ function ProfilePage() {
437437
<body>
438438
<h1>Alice</h1>
439439
<p>Photographer and traveler.</p>
440-
<Suspense fallback={<p>Loading posts...</p>}>
440+
<Suspense fallback={<p>Loading posts...</p>}>
441441
<Posts />
442442
</Suspense>
443443
</body>
@@ -2259,9 +2259,9 @@ During a Transition, React avoids hiding already revealed content. However, when
22592259
<ProfilePage key={queryParams.id} />
22602260
```
22612261
2262-
With a different `key`, React treats the profiles as different components and resets the Suspense boundary during navigation. Suspense-integrated routers do this automatically.
2262+
With a different `key`, React treats the profiles as different content and resets the Suspense boundary during navigation. The `key` can go on the boundary itself or on a component above it. Suspense-integrated routers should do this automatically.
22632263
2264-
In the example below, opening the profile page loads the first profile. Switching tabs navigates to a different profile, and the `key` resets the boundary, so the fallback shows instead of the previous user's bio. Try removing the `key`: the previous bio stays visible while the next one loads:
2264+
In the example below, opening the profile page loads the first profile. Pressing "Bob" navigates to a different profile, and the `key` resets the boundary, so the fallback shows instead of the previous user's bio. Try removing the `key`: the previous bio stays visible while the next one loads:
22652265
22662266
<Sandpack>
22672267
@@ -2325,7 +2325,6 @@ export default function Bio({ bioPromise }) {
23252325
```js src/data.js hidden
23262326
// Note: the way you would do data fetching depends on
23272327
// the framework that you use together with Suspense.
2328-
// Normally, the caching logic would be inside a framework.
23292328

23302329
export async function fetchBio(userId) {
23312330
// Add a fake delay to make waiting noticeable.
@@ -2376,7 +2375,7 @@ The server HTML will include the loading indicator. It will be replaced by the `
23762375
23772376
### Waiting for a stylesheet to load {/*waiting-for-a-stylesheet-to-load*/}
23782377
2379-
A stylesheet rendered with [`<link rel="stylesheet">` and a `precedence` prop](/reference/react-dom/components/link#special-rendering-behavior) blocks the boundary until the stylesheet loads, up to a timeout, so the content never appears unstyled.
2378+
A stylesheet rendered with [`<link rel="stylesheet">` and a `precedence` prop](/reference/react-dom/components/link#special-rendering-behavior) blocks the boundary until the stylesheet loads, up to a timeout, so the content doesn't appear unstyled.
23802379
23812380
In the example below, the `Card` component renders a stylesheet with `precedence`. Press "Show card": React shows the fallback until the stylesheet has loaded, and then reveals the card with its styles applied:
23822381
@@ -2392,7 +2391,7 @@ function Card({ href }) {
23922391
return (
23932392
<>
23942393
<link rel="stylesheet" href={href} precedence="default" />
2395-
<div className="fancy-card">This card is styled by the stylesheet.</div>
2394+
<div className="fancy-card">This card uses a font from the stylesheet.</div>
23962395
</>
23972396
);
23982397
}
@@ -2683,7 +2682,7 @@ Where you place the `<ViewTransition>` relative to the boundary determines wheth
26832682
26842683
### Waiting for a font to load {/*waiting-for-a-font-to-load*/}
26852684
2686-
<CanaryBadge /> When a [`<ViewTransition>`](/reference/react/ViewTransition) animates a boundary's reveal, React also waits for new fonts the content introduces, up to a timeout, so the text doesn't flash with a fallback font. This doesn't happen by default outside a `<ViewTransition>`.
2685+
<CanaryBadge /> When a [`<ViewTransition>`](/reference/react/ViewTransition) animates a boundary's reveal, React also waits for new fonts the content introduces, up to a timeout, so the text doesn't flash with a fallback font. This only happens during a `<ViewTransition>` update.
26872686
26882687
In the example below, the `Quote` component suspends while its data loads. Rendering the quote starts its font download, so React keeps the fallback visible until the font has loaded, and the quote appears already in its font:
26892688
@@ -2700,7 +2699,7 @@ function Quote({ fontSrc }) {
27002699
const quote = use(fetchQuote());
27012700
return (
27022701
<>
2703-
<style href="fancy-font" precedence="default">
2702+
<style href={fontSrc} precedence="default">
27042703
{`@font-face {
27052704
font-family: 'Fancy';
27062705
src: url(${fontSrc}) format('truetype');
@@ -2727,7 +2726,7 @@ export default function App() {
27272726
</button>
27282727
{fontSrc && (
27292728
<ViewTransition>
2730-
<Suspense fallback={<p className="quote">⌛ Loading...</p>}>
2729+
<Suspense fallback={<p className="quote">⌛ Loading quote...</p>}>
27312730
<Quote fontSrc={fontSrc} />
27322731
</Suspense>
27332732
</ViewTransition>
@@ -2788,7 +2787,7 @@ export function fetchQuote() {
27882787
27892788
### Waiting for an image to load {/*waiting-for-an-image-to-load*/}
27902789
2791-
<CanaryBadge /> Images work the same way: when a [`<ViewTransition>`](/reference/react/ViewTransition) animates a boundary's reveal, React waits for visible images in the content to load before revealing the content, so the animation doesn't finish on a half-loaded image. This doesn't happen by default outside a `<ViewTransition>`. Adding an `onLoad` handler opts a specific image out, even inside a `<ViewTransition>`.
2790+
<CanaryBadge /> Images work the same way: when a [`<ViewTransition>`](/reference/react/ViewTransition) animates a boundary's reveal, React waits for visible images to load, up to a timeout, so the animation doesn't start with a half-loaded image. This only happens during a `<ViewTransition>` update. Adding an `onLoad` handler opts a specific image out, even inside a `<ViewTransition>`.
27922791
27932792
In the example below, the boundary shows its fallback until the portrait has loaded:
27942793
@@ -2797,36 +2796,35 @@ In the example below, the boundary shows its fallback until the portrait has loa
27972796
```js
27982797
import { ViewTransition, Suspense, useState, startTransition } from 'react';
27992798

2800-
function Scientist() {
2799+
const imageUrl = 'https://react.dev/images/docs/scientists/MK3eW3Am.jpg';
2800+
2801+
function Scientist({ src }) {
28012802
return (
28022803
<div className="card">
2803-
<img
2804-
src="https://react.dev/images/docs/scientists/MK3eW3Am.jpg"
2805-
alt="Katherine Johnson"
2806-
width={100}
2807-
height={100}
2808-
/>
2804+
<img src={src} alt="Katherine Johnson" width={100} height={100} />
28092805
<p>Katherine Johnson</p>
28102806
</div>
28112807
);
28122808
}
28132809

28142810
export default function App() {
2815-
const [show, setShow] = useState(false);
2811+
const [src, setSrc] = useState(null);
28162812
return (
28172813
<>
28182814
<button
28192815
onClick={() => {
28202816
startTransition(() => {
2821-
setShow(true);
2817+
// Add a unique parameter so the image isn't cached,
2818+
// and every run shows the boundary waiting.
2819+
setSrc(imageUrl + '?t=' + Date.now());
28222820
});
28232821
}}>
28242822
Show scientist
28252823
</button>
2826-
{show && (
2824+
{src && (
28272825
<ViewTransition>
2828-
<Suspense fallback={<p>⌛ Loading...</p>}>
2829-
<Scientist />
2826+
<Suspense fallback={<p>⌛ Loading image...</p>}>
2827+
<Scientist src={src} />
28302828
</Suspense>
28312829
</ViewTransition>
28322830
)}

0 commit comments

Comments
 (0)