Skip to content

Commit 4b66824

Browse files
committed
Clarify Suspense image example
1 parent 4756b2d commit 4b66824

1 file changed

Lines changed: 31 additions & 35 deletions

File tree

‎src/content/reference/react/Suspense.md‎

Lines changed: 31 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -3053,21 +3053,23 @@ hr {
30533053
30543054
When a [`<ViewTransition>`](/reference/react/ViewTransition) animates a Suspense 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>`.
30553055
3056-
In the example below, the Suspense boundary is wrapped in a `<ViewTransition>` and shows a profile skeleton until the portrait has loaded.
3057-
3058-
For comparison, the second button performs the same update without React. Nothing waits for the image, so the card appears immediately and the image pops in when it loads:
3056+
In this example, [`startTransition`](/reference/react/startTransition) marks both state updates as Transitions. Compare what happens when React renders the image inside and outside a `<ViewTransition>`:
30593057
30603058
<Sandpack>
30613059
30623060
```js
3063-
import { ViewTransition, Suspense, useState, startTransition } from 'react';
3061+
import {
3062+
ViewTransition,
3063+
Suspense,
3064+
useState,
3065+
startTransition,
3066+
} from 'react';
30643067
import { freshImageUrl } from './image.js';
3065-
import VanillaProfile from './VanillaProfile.js';
30663068

30673069
function Profile({ src }) {
30683070
return (
30693071
<div className="card">
3070-
<img src={src} alt="Jack Pope" width={80} height={80} />
3072+
<img src={src} alt="" width={80} height={80} />
30713073
<p>Jack Pope</p>
30723074
</div>
30733075
);
@@ -3083,47 +3085,39 @@ function ProfilePlaceholder() {
30833085
}
30843086

30853087
export default function App() {
3086-
const [src, setSrc] = useState(null);
3088+
const [viewTransitionSrc, setViewTransitionSrc] = useState(null);
3089+
const [plainSrc, setPlainSrc] = useState(null);
30873090
return (
30883091
<>
30893092
<button
30903093
onClick={() => {
30913094
startTransition(() => {
3092-
setSrc(freshImageUrl());
3095+
setViewTransitionSrc(freshImageUrl());
30933096
});
30943097
}}>
3095-
Show profile
3098+
Show profile with View Transition
30963099
</button>
3097-
{src && (
3100+
{viewTransitionSrc && (
30983101
<ViewTransition>
30993102
<Suspense fallback={<ProfilePlaceholder />}>
3100-
<Profile src={src} />
3103+
<Profile src={viewTransitionSrc} />
31013104
</Suspense>
31023105
</ViewTransition>
31033106
)}
31043107
<hr />
3105-
<VanillaProfile />
3106-
</>
3107-
);
3108-
}
3109-
```
3110-
3111-
```js src/VanillaProfile.js
3112-
import { useRef } from 'react';
3113-
import { freshImageUrl } from './image.js';
3114-
3115-
export default function VanillaProfile() {
3116-
const ref = useRef(null);
3117-
function show() {
3118-
ref.current.innerHTML = `<div class="card">
3119-
<img src="${freshImageUrl()}" alt="Jack Pope" width="80" height="80" />
3120-
<p>Jack Pope</p>
3121-
</div>`;
3122-
}
3123-
return (
3124-
<>
3125-
<button onClick={show}>Show profile (without React)</button>
3126-
<div ref={ref} />
3108+
<button
3109+
onClick={() => {
3110+
startTransition(() => {
3111+
setPlainSrc(freshImageUrl());
3112+
});
3113+
}}>
3114+
Show profile without View Transition
3115+
</button>
3116+
{plainSrc && (
3117+
<Suspense fallback={<ProfilePlaceholder />}>
3118+
<Profile src={plainSrc} />
3119+
</Suspense>
3120+
)}
31273121
</>
31283122
);
31293123
}
@@ -3180,6 +3174,8 @@ hr {
31803174
31813175
</Sandpack>
31823176
3177+
Inside `<ViewTransition>`, React keeps the skeleton visible while it waits for the image, up to a timeout. Outside it, React does not wait for the image before committing the card.
3178+
31833179
---
31843180
31853181
### Coordinating fonts, images, and stylesheets {/*coordinating-fonts-images-and-stylesheets*/}
@@ -3202,7 +3198,7 @@ function ProfileCard({ resources }) {
32023198
<>
32033199
<link rel="stylesheet" href={resources.stylesheet} precedence="default" />
32043200
<div className="profile-card">
3205-
<img src={resources.image} alt="Jack Pope" width={80} height={80} />
3201+
<img src={resources.image} alt="" width={80} height={80} />
32063202
<div>
32073203
<p className="name">Jack Pope</p>
32083204
<p className="bio">{quote}</p>
@@ -3274,7 +3270,7 @@ export default function VanillaProfileCard() {
32743270
.bio { margin: 0; font-family: 'Caveat', sans-serif; font-size: 20px; line-height: 26px; }
32753271
</style>
32763272
<div class="profile-card">
3277-
<img src="${freshImageUrl()}" alt="Jack Pope" width="80" height="80" />
3273+
<img src="${freshImageUrl()}" alt="" width="80" height="80" />
32783274
<div>
32793275
<p class="name">Jack Pope</p>
32803276
<p class="bio">${quote}</p>

0 commit comments

Comments
 (0)