diff --git a/beta/src/content/apis/react/Suspense.md b/beta/src/content/apis/react/Suspense.md index 860b0abd4c4..2cf96b724c1 100644 --- a/beta/src/content/apis/react/Suspense.md +++ b/beta/src/content/apis/react/Suspense.md @@ -2,19 +2,257 @@ title: Suspense --- - - -This section is incomplete, please see the old docs for [Suspense.](https://reactjs.org/docs/react-api.html#reactsuspense) + - +`Suspense` is a React component that displays a fallback until its children have finished loading. - - ```js -}>{...} +}> + + ``` + +--- + +## Usage {/*usage*/} + +### Displaying a fallback while something is loading {/*displaying-a-fallback-while-something-is-loading*/} + +You can wrap any part of your application with a Suspense component. If either data or code in its children hasn't loaded yet, React will switch to rendering the `fallback` prop instead. For example: + +```js [[1, 3, ""], [2, 4, ""]] +<> + + }> + + + +``` + +Suppose that `Comments` takes longer to load than `Post`. Without a Suspense boundary, React wouldn't be able to show either component until both have loaded — `Post` would be blocked by `Comments`. + +Because of the Suspense boundary, `Post` doesn't need to wait for `Comments`. React renders `LoadingSpinner` in its place. Once `Comments` finishes loading, React replaces `LoadingSpinner` with `Comments`. + +Suspense will never show unintentional "holes" in your content. For example, if `PhotoAlbums` has loaded but `Notes` have not, with the structure below, it will still show a `LoadingIndicator` instead of the entire `Grid`: + +```js {4-7} +<> + + }> + + + + + + +``` + +To reveal nested content as it loads, you need to [add more Suspense boundaries.](#revealing-nested-content-as-it-loads) + + + +**Only Suspense-enabled data sources will activate a Suspense boundary.** These data sources are said to *suspend* when the data needed to render has not yet loaded. Currently, Suspense is only supported for: + +- [Lazy-loading components](#suspense-for-code-splitting) +- Data fetching with opinionated frameworks like [Relay](https://relay.dev/docs/guided-tour/rendering/loading-states/), [Next.js](https://nextjs.org/docs/advanced-features/react-18), [Hydrogen](https://hydrogen.shopify.dev/), and [Remix](https://remix.run/) + +Suspense-enabled data fetching without the use of an opinionated framework is not yet supported. The requirements for implementing a Suspense-enabled data source are unstable and undocumented. An official API for integrating data sources with Suspense will be released in a future version of React. + +Suspense does not detect when data is fetched inside an Effect or event handler. + + + +--- + +### Revealing nested content as it loads {/*revealing-nested-content-as-it-loads*/} + +When a component suspends, it activates the fallback of only the nearest parent Suspense boundary. This means you can nest multiple Suspense boundaries to create a loading sequence. Each Suspense boundary's fallback will be filled in as the next level of content becomes available. + +To illustrate, consider the following example: + +```js {1,4} +}> + + + }> + + + + +``` + +The sequence will be: + +- If `Post` hasn't loaded yet, `BigSpinner` is shown in place of the entire main content area. +- Once `Post` finishes loading, `BigSpinner` is replaced by the main content. +- If `Comments` hasn't loaded yet, `CommentsGlimmer` is shown in its place. +- Finally, once `Comments` finishes loading, it replaces `CommentsGlimmer`. + +--- + +### Lazy loading components with Suspense {/*suspense-for-code-splitting*/} + +The [`lazy`](/apis/react/lazy) API is powered by Suspense. When you render a component imported with `lazy`, it will suspend if it hasn't loaded yet. This allows you to display a loading indicator while your component's code is loading. + +```js {3,12-14} +import { lazy, Suspense, useState } from 'react'; + +const MarkdownPreview = lazy(() => import('./MarkdownPreview.js')); + +function MarkdownEditor() { + const [showPreview, setShowPreview] = useState(false); + // ... + return ( + <> + ... + {showPreview && ( + }> + + + )} + + ); +} +``` + +In this example, the code for `MarkdownPreview` won't be loaded until you attempt to render it. If `MarkdownPreview` hasn't loaded yet, `Loading` will be shown in its place. Try ticking the checkbox: + + + +```js App.js +import { useState, Suspense, lazy } from 'react'; +import Loading from './Loading.js'; + +const MarkdownPreview = lazy(() => delayForDemo(import('./MarkdownPreview.js'))); + +export default function MarkdownEditor() { + const [showPreview, setShowPreview] = useState(false); + const [markdown, setMarkdown] = useState('Hello, **world**!'); + return ( + <> +