Skip to content

Commit a9ea7fc

Browse files
authored
[18] Update suspense docs for unexpected fallbacks (#4500)
* [18] Update suspense docs for unexpected fallbacks * Add inline code block * Feedback fixes
1 parent 7d261d4 commit a9ea7fc

File tree

2 files changed

+52
-2
lines changed

2 files changed

+52
-2
lines changed

content/docs/code-splitting.md

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,52 @@ function MyComponent() {
139139
}
140140
```
141141

142+
### Avoiding fallbacks
143+
Any component may suspend as a result of rendering, even components that were already shown to the user. In order for screen content to always be consistent, if an already shown component suspends, React has to hide its tree up to the closest `<Suspense>` boundary. However, from the user's perspective, this can be disorienting.
144+
145+
Consider this tab switcher:
146+
147+
```js
148+
import React, { Suspense } from 'react';
149+
import Tabs from './Tabs';
150+
import Glimmer from './Glimmer';
151+
152+
const Comments = React.lazy(() => import('./Comments'));
153+
const Photos = React.lazy(() => import('./Photos'));
154+
155+
function MyComponent() {
156+
const [tab, setTab] = React.useState('photos');
157+
158+
function handleTabSelect(tab) {
159+
setTab(tab);
160+
};
161+
162+
return (
163+
<div>
164+
<Tabs onTabSelect={handleTabSelect} />
165+
<Suspense fallback={<Glimmer />}>
166+
{tab === 'photos' ? <Photos /> : <Comments />}
167+
</Suspense>
168+
</div>
169+
);
170+
}
171+
172+
```
173+
174+
In this example, if tab gets changed from `'photos'` to `'comments'`, but `Comments` suspends, the user will see a glimmer. This makes sense because the user no longer wants to see `Photos`, the `Comments` component is not ready to render anything, and React needs to keep the user experience consistent, so it has no choice but to show the `Glimmer` above.
175+
176+
However, sometimes this user experience is not desirable. In particular, it is sometimes better to show the "old" UI while the new UI is being prepared. You can use the new [`startTransition`](/docs/react-api.html#starttransition) API to make React do this:
177+
178+
```js
179+
function handleTabSelect(tab) {
180+
startTransition(() => {
181+
setTab(tab);
182+
});
183+
}
184+
```
185+
186+
Here, you tell React that setting tab to `'comments'` is not an urgent update, but is a [transition](/docs/react-api.html#transitions) that may take some time. React will then keep the old UI in place and interactive, and will switch to showing `<Comments />` when it is ready. See [Transitions](/docs/react-api.html#transitions) for more info.
187+
142188
### Error boundaries {#error-boundaries}
143189

144190
If the other module fails to load (for example, due to network failure), it will trigger an error. You can handle these errors to show a nice user experience and manage recovery with [Error Boundaries](/docs/error-boundaries.html). Once you've created your Error Boundary, you can use it anywhere above your lazy components to display an error state when there's a network error.

content/docs/reference-react.md

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -344,7 +344,9 @@ Note that rendering `lazy` components requires that there's a `<React.Suspense>`
344344
345345
### `React.Suspense` {#reactsuspense}
346346
347-
`React.Suspense` lets you specify the loading indicator in case some components in the tree below it are not yet ready to render. Today, lazy loading components is the **only** use case supported by `<React.Suspense>`:
347+
`React.Suspense` lets you specify the loading indicator in case some components in the tree below it are not yet ready to render. In the future we plan to let `Suspense` handle more scenarios such as data fetching. You can read about this in [our roadmap](/blog/2018/11/27/react-16-roadmap.html).
348+
349+
Today, lazy loading components is the **only** use case supported by `<React.Suspense>`:
348350
349351
```js
350352
// This component is loaded dynamically
@@ -364,7 +366,9 @@ function MyComponent() {
364366
365367
It is documented in our [code splitting guide](/docs/code-splitting.html#reactlazy). Note that `lazy` components can be deep inside the `Suspense` tree -- it doesn't have to wrap every one of them. The best practice is to place `<Suspense>` where you want to see a loading indicator, but to use `lazy()` wherever you want to do code splitting.
366368

367-
While this is not supported today, in the future we plan to let `Suspense` handle more scenarios such as data fetching. You can read about this in [our roadmap](/blog/2018/11/27/react-16-roadmap.html).
369+
> Note
370+
>
371+
> For content that is already shown to the user, switching back to a loading indicator can be disorienting. It is sometimes better to show the "old" UI while the new UI is being prepared. To do this, you can use the new transition APIs [`startTransition`](#starttransition) and [`useTransition`](/docs/hooks-reference.html#usetransition) to mark updates as transitions and avoid unexpected fallbacks.
368372

369373
### `React.startTransition` {#starttransition}
370374

0 commit comments

Comments
 (0)