<Suspense>Edit this page
A 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 it is non-blocking in 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.
Here's an example of a
Suspense component that shows a loading spinner while the
User component is loading.
<Suspense> is triggered whenever a resource is read under the suspense boundary, and waits until all resources read
under the suspense boundary have resolved. Often, however, you may not want this behavior. For example, if your entire page is
wrapped in suspense, you may not want a resource that only populates a certain part of the page to trigger suspense.
In that case, you can wrap that resource usage its own suspense boundary, and the resource will only trigger the
closest suspense boundary.
For example, in the code below, only the
title() resource will trigger the top level suspense boundary, and only the
resouce will trigger the nested suspense boundary:
The Purpose of <Suspense>
To 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.
Our example use case is to display a user profile. A naive snippet would look like this:
In this code,
profile() starts as
undefined, and when the fetcher code finishes, resolves to an object with
divs are already created and attached to the document body, albeit with empty text nodes. Once the resource resolves, the
divs are updated with the appropriate data.
The 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:
In 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.
On 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
divs. But in our second example (using
divs 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).
We can have the best of both worlds by using <Suspense>:
In this case, the
divs are created immediately, but instead of being attached to the document body, the fallback is shown. Once the resource resolves, the text in the
divs is updated, and then they are attached to the document (and the fallback removed).
It is important to note that 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.
With this in mind, we can understand that there isn't much gained from suspense in the following code:
In this code, we don't create any DOM nodes inside <Suspense> before the resource resolves, so it is pretty much the same as the second example where we only used
Suspense is triggered by reading a resource inside the <Suspense>
boundary. Components wrapped with suspense still run fully, just as they would
without suspense. However, code wrapped in
run after the resource resolves.
|The fallback component to render while the children are loading.