Ver código fonte

fix(runtime-core): avoid traversing static children for vnodes w/ PatchFlags.BAIL (#11115)

close #10547
Tycho 1 ano atrás
pai
commit
b557d3fb8a

+ 59 - 0
packages/runtime-core/__tests__/rendererFragment.spec.ts

@@ -3,6 +3,7 @@ import {
   NodeOpTypes,
   type TestElement,
   TestNodeTypes,
+  type VNode,
   createBlock,
   createCommentVNode,
   createTextVNode,
@@ -316,6 +317,64 @@ describe('renderer: fragment', () => {
     )
   })
 
+  // #10547
+  test('`template` fragment w/ render function', () => {
+    const renderFn = (vnode: VNode) => {
+      return (
+        openBlock(),
+        createBlock(
+          Fragment,
+          null,
+          [createTextVNode('text'), (openBlock(), createBlock(vnode))],
+          PatchFlags.STABLE_FRAGMENT,
+        )
+      )
+    }
+
+    const root = nodeOps.createElement('div')
+    const foo = h('div', ['foo'])
+    const bar = h('div', [h('div', 'bar')])
+
+    render(renderFn(foo), root)
+    expect(serializeInner(root)).toBe(`text<div>foo</div>`)
+
+    render(renderFn(bar), root)
+    expect(serializeInner(root)).toBe(`text<div><div>bar</div></div>`)
+
+    render(renderFn(foo), root)
+    expect(serializeInner(root)).toBe(`text<div>foo</div>`)
+  })
+
+  // #10547
+  test('`template` fragment w/ render function + keyed vnode', () => {
+    const renderFn = (vnode: VNode) => {
+      return (
+        openBlock(),
+        createBlock(
+          Fragment,
+          null,
+          [createTextVNode('text'), (openBlock(), createBlock(vnode))],
+          PatchFlags.STABLE_FRAGMENT,
+        )
+      )
+    }
+
+    const root = nodeOps.createElement('div')
+    const foo = h('div', { key: 1 }, [h('div', 'foo')])
+    const bar = h('div', { key: 2 }, [h('div', 'bar'), h('div', 'bar')])
+
+    render(renderFn(foo), root)
+    expect(serializeInner(root)).toBe(`text<div><div>foo</div></div>`)
+
+    render(renderFn(bar), root)
+    expect(serializeInner(root)).toBe(
+      `text<div><div>bar</div><div>bar</div></div>`,
+    )
+
+    render(renderFn(foo), root)
+    expect(serializeInner(root)).toBe(`text<div><div>foo</div></div>`)
+  })
+
   // #6852
   test('`template` keyed fragment w/ text', () => {
     const root = nodeOps.createElement('div')

+ 2 - 1
packages/runtime-core/src/renderer.ts

@@ -2473,7 +2473,8 @@ export function traverseStaticChildren(n1: VNode, n2: VNode, shallow = false) {
           c2 = ch2[i] = cloneIfMounted(ch2[i] as VNode)
           c2.el = c1.el
         }
-        if (!shallow) traverseStaticChildren(c1, c2)
+        if (!shallow && c2.patchFlag !== PatchFlags.BAIL)
+          traverseStaticChildren(c1, c2)
       }
       // #6852 also inherit for text nodes
       if (c2.type === Text) {