Prechádzať zdrojové kódy

fix(runtime-core): fix dynamic node tracking in dynamic component that resolves to plain elements

fix #1039
Evan You 6 rokov pred
rodič
commit
dcf2458fa8

+ 21 - 0
packages/runtime-core/__tests__/vnode.spec.ts

@@ -337,6 +337,27 @@ describe('vnode', () => {
       ]))
       expect(vnode.dynamicChildren).toStrictEqual([vnode1])
     })
+
+    // #1039
+    // <component :is="foo">{{ bar }}</component>
+    // - content is compiled as slot
+    // - dynamic component reoslves to plain element, but as a block
+    // - block creation disables its own tracking, accidentally causing the
+    //   slot content (called during the block node creation) to be missed
+    test('element block should track normalized slot children', () => {
+      const hoist = createVNode('div')
+      let vnode1
+      const vnode = (openBlock(),
+      createBlock('div', null, {
+        default: () => {
+          return [
+            hoist,
+            (vnode1 = createVNode('div', null, 'text', PatchFlags.TEXT))
+          ]
+        }
+      }))
+      expect(vnode.dynamicChildren).toStrictEqual([vnode1])
+    })
   })
 
   describe('transformVNodeArgs', () => {

+ 11 - 5
packages/runtime-core/src/vnode.ts

@@ -177,10 +177,14 @@ export function createBlock(
   patchFlag?: number,
   dynamicProps?: string[]
 ): VNode {
-  // avoid a block with patchFlag tracking itself
-  shouldTrack--
-  const vnode = createVNode(type, props, children, patchFlag, dynamicProps)
-  shouldTrack++
+  const vnode = createVNode(
+    type,
+    props,
+    children,
+    patchFlag,
+    dynamicProps,
+    true /* isBlock: prevent a block from tracking itself */
+  )
   // save current block children on the block vnode
   vnode.dynamicChildren = currentBlock || EMPTY_ARR
   // close block
@@ -244,7 +248,8 @@ function _createVNode(
   props: (Data & VNodeProps) | null = null,
   children: unknown = null,
   patchFlag: number = 0,
-  dynamicProps: string[] | null = null
+  dynamicProps: string[] | null = null,
+  isBlockNode = false
 ): VNode {
   if (!type) {
     if (__DEV__) {
@@ -337,6 +342,7 @@ function _createVNode(
   // the next vnode so that it can be properly unmounted later.
   if (
     shouldTrack > 0 &&
+    !isBlockNode &&
     currentBlock &&
     // the EVENTS flag is only for hydration and if it is the only flag, the
     // vnode should not be considered dynamic due to handler caching.