fix(runtime-core): fix cases of reused children arrays in render functions (#3670)
fix #3666
This commit is contained in:
parent
ff50e8d78c
commit
a641eb201f
@ -296,4 +296,39 @@ describe('renderer: component', () => {
|
||||
expect(serializeInner(root)).toBe(`<h1>1</h1>`)
|
||||
})
|
||||
})
|
||||
|
||||
test('the component VNode should be cloned when reusing it', () => {
|
||||
const Child = {
|
||||
setup(props: any, { slots }: SetupContext) {
|
||||
return () => {
|
||||
const c = slots.default!()
|
||||
return [c, c, c]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const ids: number[] = []
|
||||
const Comp = {
|
||||
render: () => h('h1'),
|
||||
beforeUnmount() {
|
||||
ids.push((this as any).$.uid)
|
||||
}
|
||||
}
|
||||
|
||||
const App = {
|
||||
setup() {
|
||||
return () => {
|
||||
return h(Child, () => [h(Comp)])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const root = nodeOps.createElement('div')
|
||||
render(h(App), root)
|
||||
expect(serializeInner(root)).toBe(`<h1></h1><h1></h1><h1></h1>`)
|
||||
|
||||
render(null, root)
|
||||
expect(serializeInner(root)).toBe(``)
|
||||
expect(ids).toEqual([ids[0], ids[0] + 1, ids[0] + 2])
|
||||
})
|
||||
})
|
||||
|
@ -603,11 +603,16 @@ export function normalizeVNode(child: VNodeChild): VNode {
|
||||
return createVNode(Comment)
|
||||
} else if (isArray(child)) {
|
||||
// fragment
|
||||
return createVNode(Fragment, null, child)
|
||||
return createVNode(
|
||||
Fragment,
|
||||
null,
|
||||
// #3666, avoid reference pollution when reusing vnode
|
||||
child.slice()
|
||||
)
|
||||
} else if (typeof child === 'object') {
|
||||
// already vnode, this should be the most common since compiled templates
|
||||
// always produce all-vnode children arrays
|
||||
return child.el === null ? child : cloneVNode(child)
|
||||
return cloneIfMounted(child)
|
||||
} else {
|
||||
// strings and numbers
|
||||
return createVNode(Text, null, String(child))
|
||||
|
Loading…
Reference in New Issue
Block a user