Skip to content

Commit

Permalink
feat(Suspense): add suspensible prop information
Browse files Browse the repository at this point in the history
Signed-off-by: GitHub <[email protected]>
  • Loading branch information
ferferga committed Apr 4, 2024
1 parent 4d838ce commit 0d85bd8
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 0 deletions.
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

0 comments on commit 0d85bd8

Please sign in to comment.