Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(Suspense): add suspensible prop information #2785

Merged
merged 1 commit into from Apr 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/api/built-in-components.md
Expand Up @@ -318,6 +318,7 @@ Used for orchestrating nested async dependencies in a component tree.
```ts
interface SuspenseProps {
timeout?: string | number
suspensible?: boolean
}
```

Expand All @@ -333,4 +334,7 @@ Used for orchestrating nested async dependencies in a component tree.

If it encounters async dependencies ([Async Components](/guide/components/async) and components with [`async setup()`](/guide/built-ins/suspense#async-setup)) while rendering the default slot, it will wait until all of them are resolved before displaying the default slot.

By setting the Suspense as `suspensible`, all the async dependency handling
will be handled by the parent Suspense. See [implementation details](https://github.com/vuejs/core/pull/6736)

- **See also** [Guide - Suspense](/guide/built-ins/suspense)
34 changes: 34 additions & 0 deletions src/guide/built-ins/suspense.md
Expand Up @@ -133,6 +133,40 @@ The following example shows how to nest these components so that they all behave

Vue Router has built-in support for [lazily loading components](https://router.vuejs.org/guide/advanced/lazy-loading.html) using dynamic imports. These are distinct from async components and currently they will not trigger `<Suspense>`. However, they can still have async components as descendants and those can trigger `<Suspense>` in the usual way.

## Nested Suspense

When we have multiple async components (common for nested or layout-based routes) like this:

```vue-html
<Suspense>
<component :is="DynamicAsyncOuter">
<component :is="DynamicAsyncInner" />
</component>
</Suspense>
```

`<Suspense>` creates a boundary that will resolve all the async components down the tree,
as expected. However, when we change `DynamicAsyncOuter`, `<Suspense>` awaits it correctly, but when we change `DynamicAsyncInner`,
the nested `DynamicAsyncInner` renders an empty node until it has been resolved (instead of the previous one or fallback slot).

In order to solve that, we could have a nested suspense to handle the patch for the nested component, like:

```vue-html
<Suspense>
<component :is="DynamicAsyncOuter">
<Suspense suspensible> <!-- this -->
<component :is="DynamicAsyncInner" />
</Suspense>
</component>
</Suspense>
```

If you don't set the `suspensible` prop, the inner `<Suspense>` will be treated like a sync component by the parent `<Suspense>`.
That means that it has its own fallback slot and if both `Dynamic` components change at the same time,
there might be empty nodes and multiple patching cycles while the child `<Suspense>` is loading its own dependency tree,
which might not be desirable. When it's set, all the async dependency handling is given to the parent `<Suspense>` (including the events emitted)
and the inner `<Suspense>` serves solely as another boundary for the dependency resolution and patching.

---

**Related**
Expand Down