]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
fix(suspense): fix dynamicChildren tracking when suspense root is a block itself
authorEvan You <yyx990803@gmail.com>
Wed, 28 Jul 2021 20:49:34 +0000 (16:49 -0400)
committerEvan You <yyx990803@gmail.com>
Wed, 28 Jul 2021 20:49:34 +0000 (16:49 -0400)
e.g. `<slot>` inside suspense

fix #4183, fix #4198

packages/runtime-core/__tests__/rendererOptimizedMode.spec.ts
packages/runtime-core/src/components/Suspense.ts

index 90e3e28b88ae683415e3af9bc3d73834b6ebb862..82acc4bdb5d5034a415c024384ac87bd484da1a7 100644 (file)
@@ -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('<div><div>true</div></div>')
   })
 
+  // #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('<div>true</div>')
+
+    show.value = false
+    await nextTick()
+    expect(inner(root)).toBe('<!--v-if-->')
+    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
index ffc900180fe91123bf1df58269f4ce4abf5f2c8a..6a27b7c2d26fd0a491914d9da8339b2a6bd76ba3 100644 (file)
@@ -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