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: introduce suspensible option to <Suspense> to fix suspense flicks #6736

Merged
merged 7 commits into from Apr 21, 2023

Conversation

antfu
Copy link
Member

@antfu antfu commented Sep 24, 2022

Resolve #5513

This PR introduces a new prop for Suspense - <Suspense suspensible> to allow nested suspense to be captured by the parent suspense.

Reproduction

Thanks a lot to @danielroe for the great reproduction:
https://stackblitz.com/edit/vitejs-vite-ftc8df?file=src%2FApp.vue

The Problem

When we have multiple async components like:

<Suspense>
  <AsyncOuter>
    <AsyncInner />
  </AsyncOuter>
</Suspense>

Suspense creates a boundary that will resolve all the async components down the tree, which is how it is expected to be.

When both async components need to be async (nested route page for example)

<Suspense>
  <component :is="DynamicAsyncOuter">
    <component :is="DynamicAsyncInner" />
  </component>
</Suspense>

At the initial mount, it works as expected, both DynamicAsyncOuter and DynamicAsyncInner are waited before rendering.

The problem comes with patching. When we change DynamicAsyncOuter, Suspense awaits it correctly, but when we change DynamicAsyncInner, the Suspense does not get patched causing the nested DynamicAsyncInner renders an empty node until it has been resolved, causing the flickering.

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

<Suspense>
  <component :is="DynamicAsyncOuter">
    <Suspense> <!-- this -->
      <component :is="DynamicAsyncInner" />
    </Suspense>
  </component>
</Suspense>

This solves the patching issue but makes the mounting break as the nested Suspense now behaves like a sync component and has its own fallback.

The Solution

This PR introduces a new prop for Suspense - <Suspense suspensible> to allow nested suspense to be captured by the parent suspense. Making it able to handle async patching for branches and keep the mount as one render to avoid flickering.

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

Unlike async components, Suspsense's suspensible prop is the default to false in order to not break the current behavior.

@antfu antfu added scope: suspense ❗ p4-important Priority 4: this fixes bugs that violate documented behavior, or significantly improves perf. labels Sep 24, 2022
Co-authored-by: Damian Głowala <48835293+DamianGlowala@users.noreply.github.com>
@antfu antfu added 🔨 p3-minor-bug Priority 3: this fixes a bug, but is an edge case that only affects very specific usage. and removed ❗ p4-important Priority 4: this fixes bugs that violate documented behavior, or significantly improves perf. labels Oct 10, 2022
@antfu antfu changed the title feat: introduce suspensible option to <Suspense> feat: introduce suspensible option to <Suspense> to fix suspense flicks Oct 10, 2022
@BlakeB415
Copy link

Can we get this merged soon?

@adamcikado
Copy link

Hey @DamianGlowala , is there any reason why this isn't merged yet? Thank you!

@DamianGlowala
Copy link

From the message I received from @antfu, this PR needs feedback from the core team. There isn't any timescale for having this merged at the moment.

For Nuxt users: if this PR takes longer than expected, it might be patched directly in Nuxt at some point.

@yinfoyuan
Copy link

Can we get this merged soon?

@DamianGlowala
Copy link

@yyx990803 any chances to review this PR and consider including it in v3.3.0 release should there be no blocking issues? 🙏

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
🔨 p3-minor-bug Priority 3: this fixes a bug, but is an edge case that only affects very specific usage. scope: suspense
Projects
Status: Done
Development

Successfully merging this pull request may close these issues.

Nested components in detached branch render while being detached
6 participants