Files
Devour/devour_data/docs/suspense.json
T
Tomas Dvorak 898a3c303f update
2026-02-24 10:33:59 +01:00

17 lines
7.8 KiB
JSON

{
"id": "22e5d1cef33b52ba659d93c1",
"source": "solid:signals",
"type": "github-document",
"title": "suspense",
"content": "---\ntitle: \u003cSuspense\u003e\norder: 5\nuse_cases: \u003e-\n async data, loading states, data fetching, api calls, lazy loading, user\n experience\ntags:\n - suspense\n - async\n - loading\n - resources\n - components\n - data-fetching\nversion: '1.0'\ndescription: \u003e-\n Handle async operations elegantly in SolidJS with Suspense. Show loading\n states while resources load without blocking UI rendering.\n---\n\nA component that tracks all resources read under it and shows a fallback placeholder state until they are resolved. What makes `Suspense` different than `Show` is that it is non-blocking in the sense that both branches exist at the same time even if not currently in the DOM. This means that the fallback can be rendered while the children are loading. This is useful for loading states and other asynchronous operations.\n\n```tsx\nimport { Suspense } from \"solid-js\"\nimport type { JSX } from \"solid-js\"\n\nfunction Suspense(props: {\n\tfallback?: JSX.Element\n\tchildren: JSX.Element\n}): JSX.Element\n\n```\n\nHere's an example of a `Suspense` component that shows a loading spinner while the `User` component is loading.\n\n```tsx\n\u003cSuspense fallback={\u003cLoadingSpinner /\u003e}\u003e\n\t\u003cAsyncComponent /\u003e\n\u003c/Suspense\u003e\n\n```\n\n## Nested Suspense\n\n`\u003cSuspense\u003e` is triggered whenever a resource is read under the suspense boundary, and waits until all resources read\nunder the suspense boundary have resolved. Often, however, you may not want this behavior. For example, if your entire page is\nwrapped in suspense, you may not want a resource that only populates a certain part of the page to trigger suspense.\nIn that case, you can wrap that resource usage in its own suspense boundary, and the resource will only trigger the\nclosest suspense boundary.\n\nFor example, in the code below, only the `title()` resource will trigger the top level suspense boundary, and only the `data()`\nresource will trigger the nested suspense boundary:\n\n```jsx\nconst MyComponent = () =\u003e {\n\tconst [title] = createResource(async () =\u003e { /* fetcher code here */ })\n\tconst [data] = createResource(async () =\u003e { /* fetcher code here */ })\n\t\u003cSuspense\u003e\n\t\t\u003ch1\u003e{title()}\u003c/h1\u003e\n\t\t\u003cSuspense\u003e\n\t\t\t\u003cDataComponent\u003e{data()}\u003c/DataComponent\u003e\n\t\t\u003c/Suspense\u003e\n\t\u003c/Suspense\u003e\n}\n\n```\n\n## The purpose of `\u003cSuspense\u003e`\n\nTo understand the purpose of suspense, let's consider the following code snippets. These snippets will have some drawbacks which we will solve by using suspense. We will also see how it is possible to use `Suspense` yet not reap its benefits.\n\nOur example use case is to display a user profile. A naive snippet would look like this:\n\n```jsx\nconst MyComponentWithOptionalChaining = () =\u003e {\n\tconst [profile] = createResource(async () =\u003e {\n\t\t/* fetcher code here */\n\t})\n\treturn (\n\t\t\u003c\u003e\n\t\t\t\u003cdiv\u003e{profile()?.name}\u003c/div\u003e\n\t\t\t\u003cdiv\u003e{profile()?.email}\u003c/div\u003e\n\t\t\u003c/\u003e\n\t)\n}\n\n```\n\nIn this code, `profile()` starts as `undefined`, and when the fetcher code finishes, resolves to an object with `name` and `email` properties. Although the resource has not resolved yet, the two `div`s are already created and attached to the document body, albeit with empty text nodes. Once the resource resolves, the `div`s are updated with the appropriate data.\n\nThe downside of this approach is that the user is shown an empty component - let's see if we can do better than that in this next snippet:\n\n```jsx\nconst MyComponentWithShow = () =\u003e {\n\tconst [profile] = createResource(async () =\u003e {\n\t\t/* fetcher code here */\n\t})\n\treturn (\n\t\t\u003cShow when={profile()} fallback={\u003cdiv\u003efetching user data\u003c/div\u003e}\u003e\n\t\t\t\u003cdiv\u003e{profile().name}\u003c/div\u003e\n\t\t\t\u003cdiv\u003e{profile().email}\u003c/div\u003e\n\t\t\u003c/Show\u003e\n\t)\n}\n\n```\n\nIn this snippet, we first show a fallback when the resource hasn't resolved yet, and then switch to showing the profile data once it has. This results in a better user experience.\n\nOn the other hand, there is a slight downside to this approach. In our first example (using optional chaining), the divs were created immediately, and once the resource resolves all that is needed to be done is to fill in the text of the `div`s. But in our second example (using `\u003cShow\u003e`), the `div`s are only created once the resource has resolved, which means there is more work that needs to be done after the resource has resolved before the data can be shown to the user (of course, in this toy example the amount of DOM work is relatively trivial).\n\nWe can have the best of both worlds by using {\"\u003cSuspense\u003e\"}:\n\n```jsx\nconst MyComponentWithSuspense = () =\u003e {\n\tconst [profile] = createResource(async () =\u003e {\n\t\t/* fetcher code here */\n\t})\n\treturn (\n\t\t\u003cSuspense fallback={\u003cdiv\u003efetching user data\u003c/div\u003e}\u003e\n\t\t\t\u003cdiv\u003e{profile()?.name}\u003c/div\u003e\n\t\t\t\u003cdiv\u003e{profile()?.email}\u003c/div\u003e\n\t\t\u003c/Suspense\u003e\n\t)\n}\n```\n\nIn this case, the `div`s are created immediately, but instead of being attached to the document body, the fallback is shown. Once the resource resolves, the text in the `div`s is updated, and then they are attached to the document (and the fallback removed).\n\nIt is important to note that _the execution of the component does not pause_ when using suspense. Instead, when a resource is read under a suspense boundary, it ensures that the nodes are not attached to the document until after the resource has resolved. Suspense allows us to have the best of both worlds: do as much work as we can _before_ the resource resolves, and also show a fallback until then.\n\nWith this in mind, we can understand that there isn't much gained from suspense in the following code:\n\n```jsx\nconst MyComponentWithSuspenseAndShow = () =\u003e {\n\tconst [profile] = createResource(async () =\u003e {\n\t\t/* fetcher code here */\n\t})\n\treturn (\n\t\t\u003cSuspense fallback={\u003cdiv\u003efetching user data\u003c/div\u003e}\u003e\n\t\t\t\u003cShow when={profile()}\u003e\n\t\t\t\t\u003cdiv\u003e{profile().name}\u003c/div\u003e\n\t\t\t\t\u003cdiv\u003e{profile().email}\u003c/div\u003e\n\t\t\t\u003c/Show\u003e\n\t\t\u003c/Suspense\u003e\n\t)\n}\n```\n\nIn this code, we don't create _any_ DOM nodes inside {\"\u003cSuspense\u003e\"} before the resource resolves, so it is pretty much the same as the second example where we only used `\u003cShow\u003e`.\n\n:::note\n\tSuspense is triggered by reading a resource inside the {\"\u003cSuspense\u003e\"}{\" \"}\n\tboundary. Components wrapped with suspense still run fully, just as they would\n\twithout suspense. However, code wrapped in `onMount` and `createEffect` only\n\trun after the resource resolves.\n:::\n\n## Props\n\n| Name | Type | Description |\n| :--------- | :------------ | :--------------------------------------------------------------- |\n| `fallback` | `JSX.Element` | The fallback component to render while the children are loading. |",
"url": "https://github.com/solidjs/solid-docs/blob/HEAD/src/routes/reference/components/suspense.mdx",
"metadata": {
"path": "src/routes/reference/components/suspense.mdx",
"repo": "solidjs/solid-docs",
"repo_url": "https://github.com/solidjs/solid-docs.git",
"size": 6519,
"source_type": "github"
},
"hash": "f2912afb2327181d621e54ceeab525ec5e70f96cc6cc6634a7f7894faa93a9a6",
"timestamp": "2026-02-23T11:43:00.189211241+01:00"
}