You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
@@ -44,7 +44,7 @@ A Suspense boundary waits for its content to be ready before revealing it. Any o
44
44
45
45
- Lazy-loading component code with [`lazy`](/reference/react/lazy).
46
46
- 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).
47
-
- 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.
47
+
- 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)
48
48
- 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
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
50
- Loading images. This doesn't happen by default, but a [`<ViewTransition>`](/reference/react/ViewTransition) update waits for its images to load, up to a timeout. Adding an `onLoad` handler opts a specific image out. [See an example below.](#waiting-for-an-image-to-load)
@@ -2251,6 +2251,181 @@ main {
2251
2251
2252
2252
---
2253
2253
2254
+
### Resetting Suspense boundaries on navigation {/*resetting-suspense-boundaries-on-navigation*/}
2255
+
2256
+
During a Transition, React avoids hiding already revealed content. However, when you navigate to *different* content, such as another user's profile, you'll want the boundary to show the fallback instead of the previous content. You can express this with a `key`:
2257
+
2258
+
```js
2259
+
<ProfilePage key={queryParams.id} />
2260
+
```
2261
+
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.
2263
+
2264
+
In the example below, the `key` resets the boundary when you switch profiles, 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:
// Note: the way you would do data fetching depends on
2310
+
// the framework that you use together with Suspense.
2311
+
// Normally, the caching logic would be inside a framework.
2312
+
2313
+
exportasyncfunctionfetchBio(userId) {
2314
+
// Add a fake delay to make waiting noticeable.
2315
+
awaitnewPromise(resolve=> {
2316
+
setTimeout(resolve, 1500);
2317
+
});
2318
+
2319
+
return userId ==='alice'
2320
+
?'Alice is a photographer and traveler.'
2321
+
:'Bob collects vintage synthesizers.';
2322
+
}
2323
+
```
2324
+
2325
+
```css
2326
+
button {
2327
+
margin-right:8px;
2328
+
}
2329
+
```
2330
+
2331
+
</Sandpack>
2332
+
2333
+
---
2334
+
2335
+
### Providing a fallback for server errors and client-only content {/*providing-a-fallback-for-server-errors-and-client-only-content*/}
2336
+
2337
+
If you use one of the [streaming server rendering APIs](/reference/react-dom/server) (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.
2338
+
2339
+
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.](/reference/react/Component#static-getderivedstatefromerror) 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.
2340
+
2341
+
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:
2342
+
2343
+
```js
2344
+
<Suspense fallback={<Loading />}>
2345
+
<Chat />
2346
+
</Suspense>
2347
+
2348
+
functionChat() {
2349
+
if (typeofwindow==='undefined') {
2350
+
throwError('Chat should only render on the client.');
2351
+
}
2352
+
// ...
2353
+
}
2354
+
```
2355
+
2356
+
The server HTML will include the loading indicator. It will be replaced by the `Chat` component on the client.
2357
+
2358
+
---
2359
+
2360
+
### Waiting for a stylesheet to load {/*waiting-for-a-stylesheet-to-load*/}
2361
+
2362
+
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.
2363
+
2364
+
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:
### Animating from Suspense content {/*animating-from-suspense-content*/}
2255
2430
2256
2431
<CanaryBadge /> Suspense composes with [`<ViewTransition>`](/reference/react/ViewTransition) to animate the swap from the fallback to the content. Wrap the boundary in a `<ViewTransition>`, and React treats the swap as an update, cross-fading between the fallback and the content by default:
@@ -2493,17 +2668,19 @@ Where you place the `<ViewTransition>` relative to the boundary determines wheth
2493
2668
2494
2669
<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>`.
2495
2670
2496
-
In the example below, the `Quote` component suspends while its data loads. The browser only starts downloading a font when text first uses it, so rendering the quote starts the font download. React holds the animated reveal until the font has loaded:
2671
+
In the example below, the quote uses a new font. The browser only starts downloading a font when text first uses it, so rendering the quote starts the download. React holds the animated reveal until the font has loaded:
The best way to predict the future is to invent it.
2682
+
</p>
2683
+
);
2507
2684
}
2508
2685
2509
2686
exportdefaultfunctionApp() {
@@ -2530,28 +2707,6 @@ export default function App() {
2530
2707
}
2531
2708
```
2532
2709
2533
-
```js src/data.js hidden
2534
-
// Note: the way you would do data fetching depends on
2535
-
// the framework that you use together with Suspense.
2536
-
// Normally, the caching logic would be inside a framework.
2537
-
2538
-
let cache =null;
2539
-
2540
-
exportfunctionfetchQuote() {
2541
-
if (!cache) {
2542
-
cache =newPromise((resolve) => {
2543
-
// Add a fake delay to make waiting noticeable.
2544
-
setTimeout(() => {
2545
-
resolve(
2546
-
'The best way to predict the future is to invent it.'
2547
-
);
2548
-
}, 1500);
2549
-
});
2550
-
}
2551
-
return cache;
2552
-
}
2553
-
```
2554
-
2555
2710
```css
2556
2711
/* The browser doesn't download the font until
2557
2712
text first renders with this font family. */
@@ -2590,25 +2745,23 @@ export function fetchQuote() {
2590
2745
2591
2746
<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>`.
2592
2747
2593
-
In the example below, the `Scientist` component suspends while its data loads. When the data is ready, React holds the animated reveal until the portrait has loaded:
2748
+
In the example below, React holds the animated reveal until the portrait has loaded:
@@ -2689,45 +2819,6 @@ export function fetchScientist() {
2689
2819
2690
2820
---
2691
2821
2692
-
### Resetting Suspense boundaries on navigation {/*resetting-suspense-boundaries-on-navigation*/}
2693
-
2694
-
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`:
2695
-
2696
-
```js
2697
-
<ProfilePage key={queryParams.id} />
2698
-
```
2699
-
2700
-
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.
2701
-
2702
-
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 components, and resets the Suspense boundaries during navigation. Suspense-integrated routers should do this automatically.
2703
-
2704
-
---
2705
-
2706
-
### Providing a fallback for server errors and client-only content {/*providing-a-fallback-for-server-errors-and-client-only-content*/}
2707
-
2708
-
If you use one of the [streaming server rendering APIs](/reference/react-dom/server) (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.
2709
-
2710
-
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.](/reference/react/Component#static-getderivedstatefromerror) 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.
2711
-
2712
-
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:
2713
-
2714
-
```js
2715
-
<Suspense fallback={<Loading />}>
2716
-
<Chat />
2717
-
</Suspense>
2718
-
2719
-
functionChat() {
2720
-
if (typeofwindow==='undefined') {
2721
-
throwError('Chat should only render on the client.');
2722
-
}
2723
-
// ...
2724
-
}
2725
-
```
2726
-
2727
-
The server HTML will include the loading indicator. It will be replaced by the `Chat` component on the client.
2728
-
2729
-
---
2730
-
2731
2822
## Troubleshooting {/*troubleshooting*/}
2732
2823
2733
2824
### How do I prevent the UI from being replaced by a fallback during an update? {/*preventing-unwanted-fallbacks*/}
0 commit comments