diff --git a/packages/runtime-core/__tests__/components/Suspense.spec.ts b/packages/runtime-core/__tests__/components/Suspense.spec.ts index e98004755..bf209007d 100644 --- a/packages/runtime-core/__tests__/components/Suspense.spec.ts +++ b/packages/runtime-core/__tests__/components/Suspense.spec.ts @@ -1093,4 +1093,36 @@ describe('Suspense', () => { await nextTick() expect(root.innerHTML).toBe(`
2
`) }) + + // #2215 + test('toggling nested async setup component inside already resolved suspense', async () => { + const toggle = ref(false) + const Child = { + async setup() { + return () => h('div', 'child') + } + } + const Parent = () => h('div', ['parent', toggle.value ? h(Child) : null]) + const Comp = { + setup() { + return () => h(Suspense, () => h(Parent)) + } + } + + const root = nodeOps.createElement('div') + render(h(Comp), root) + expect(serializeInner(root)).toBe(`
parent
`) + + toggle.value = true + // wait for flush + await nextTick() + // wait for child async setup resolve + await nextTick() + // child should be rendered now instead of stuck in limbo + expect(serializeInner(root)).toBe(`
parent
child
`) + + toggle.value = false + await nextTick() + expect(serializeInner(root)).toBe(`
parent
`) + }) }) diff --git a/packages/runtime-core/src/components/Suspense.ts b/packages/runtime-core/src/components/Suspense.ts index 105af7315..1b5adfed3 100644 --- a/packages/runtime-core/src/components/Suspense.ts +++ b/packages/runtime-core/src/components/Suspense.ts @@ -542,12 +542,11 @@ function createSuspenseBoundary( }, registerDep(instance, setupRenderEffect) { - if (!suspense.pendingBranch) { - return + const isInPendingSuspense = !!suspense.pendingBranch + if (isInPendingSuspense) { + suspense.deps++ } - const hydratedEl = instance.vnode.el - suspense.deps++ instance .asyncDep!.catch(err => { handleError(err, instance, ErrorCodes.SETUP_FUNCTION) @@ -562,7 +561,6 @@ function createSuspenseBoundary( ) { return } - suspense.deps-- // retry from this component instance.asyncResolved = true const { vnode } = instance @@ -597,7 +595,8 @@ function createSuspenseBoundary( if (__DEV__) { popWarningContext() } - if (suspense.deps === 0) { + // only decrease deps count if suspense is not already resolved + if (isInPendingSuspense && --suspense.deps === 0) { suspense.resolve() } })