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(``)
+
+ 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()
}
})