Skip to content

Commit a641eb2

Browse files
authored
fix(runtime-core): fix cases of reused children arrays in render functions (#3670)
fix #3666
1 parent ff50e8d commit a641eb2

File tree

2 files changed

+42
-2
lines changed

2 files changed

+42
-2
lines changed

packages/runtime-core/__tests__/rendererComponent.spec.ts

+35
Original file line numberDiff line numberDiff line change
@@ -296,4 +296,39 @@ describe('renderer: component', () => {
296296
expect(serializeInner(root)).toBe(`<h1>1</h1>`)
297297
})
298298
})
299+
300+
test('the component VNode should be cloned when reusing it', () => {
301+
const Child = {
302+
setup(props: any, { slots }: SetupContext) {
303+
return () => {
304+
const c = slots.default!()
305+
return [c, c, c]
306+
}
307+
}
308+
}
309+
310+
const ids: number[] = []
311+
const Comp = {
312+
render: () => h('h1'),
313+
beforeUnmount() {
314+
ids.push((this as any).$.uid)
315+
}
316+
}
317+
318+
const App = {
319+
setup() {
320+
return () => {
321+
return h(Child, () => [h(Comp)])
322+
}
323+
}
324+
}
325+
326+
const root = nodeOps.createElement('div')
327+
render(h(App), root)
328+
expect(serializeInner(root)).toBe(`<h1></h1><h1></h1><h1></h1>`)
329+
330+
render(null, root)
331+
expect(serializeInner(root)).toBe(``)
332+
expect(ids).toEqual([ids[0], ids[0] + 1, ids[0] + 2])
333+
})
299334
})

packages/runtime-core/src/vnode.ts

+7-2
Original file line numberDiff line numberDiff line change
@@ -603,11 +603,16 @@ export function normalizeVNode(child: VNodeChild): VNode {
603603
return createVNode(Comment)
604604
} else if (isArray(child)) {
605605
// fragment
606-
return createVNode(Fragment, null, child)
606+
return createVNode(
607+
Fragment,
608+
null,
609+
// #3666, avoid reference pollution when reusing vnode
610+
child.slice()
611+
)
607612
} else if (typeof child === 'object') {
608613
// already vnode, this should be the most common since compiled templates
609614
// always produce all-vnode children arrays
610-
return child.el === null ? child : cloneVNode(child)
615+
return cloneIfMounted(child)
611616
} else {
612617
// strings and numbers
613618
return createVNode(Text, null, String(child))

0 commit comments

Comments
 (0)