diff --git a/packages/runtime-core/__tests__/rendererOptimizedMode.spec.ts b/packages/runtime-core/__tests__/rendererOptimizedMode.spec.ts index 90e3e28b88a..82acc4bdb5d 100644 --- a/packages/runtime-core/__tests__/rendererOptimizedMode.spec.ts +++ b/packages/runtime-core/__tests__/rendererOptimizedMode.spec.ts @@ -22,7 +22,8 @@ import { SetupContext, createApp, FunctionalComponent, - renderList + renderList, + onUnmounted } from '@vue/runtime-test' import { PatchFlags, SlotFlags } from '@vue/shared' import { SuspenseImpl } from '../src/components/Suspense' @@ -826,6 +827,55 @@ describe('renderer: optimized mode', () => { expect(inner(root)).toBe('
true
') }) + // #4183 + test('should not take unmount children fast path /w Suspense', async () => { + const show = ref(true) + const spyUnmounted = jest.fn() + + const Parent = { + setup(props: any, { slots }: SetupContext) { + return () => ( + openBlock(), + createBlock(SuspenseImpl, null, { + default: withCtx(() => [renderSlot(slots, 'default')]), + _: SlotFlags.FORWARDED + }) + ) + } + } + + const Child = { + setup() { + onUnmounted(spyUnmounted) + return () => createVNode('div', null, show.value, PatchFlags.TEXT) + } + } + + const app = createApp({ + render() { + return show.value + ? (openBlock(), + createBlock( + Parent, + { key: 0 }, + { + default: withCtx(() => [createVNode(Child)]), + _: SlotFlags.STABLE + } + )) + : createCommentVNode('v-if', true) + } + }) + + app.mount(root) + expect(inner(root)).toBe('
true
') + + show.value = false + await nextTick() + expect(inner(root)).toBe('') + expect(spyUnmounted).toHaveBeenCalledTimes(1) + }) + // #3881 // root cause: fragment inside a compiled slot passed to component which // programmatically invokes the slot. The entire slot should de-opt but diff --git a/packages/runtime-core/src/components/Suspense.ts b/packages/runtime-core/src/components/Suspense.ts index ffc900180fe..6a27b7c2d26 100644 --- a/packages/runtime-core/src/components/Suspense.ts +++ b/packages/runtime-core/src/components/Suspense.ts @@ -749,7 +749,7 @@ function normalizeSuspenseSlot(s: any) { s = singleChild } s = normalizeVNode(s) - if (block) { + if (block && !s.dynamicChildren) { s.dynamicChildren = block.filter(c => c !== s) } return s