Skip to content

Commit c9629f2

Browse files
committed
feat(runtime-core): support creating vnode from existing vnode
This allows passing vnode around with curried props and use it in places where VNodeType is expected, e.g. `<component :is=""/>`
1 parent 359b4a3 commit c9629f2

File tree

2 files changed

+26
-3
lines changed

2 files changed

+26
-3
lines changed

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

+14
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,20 @@ describe('vnode', () => {
4242
expect(vnode.props).toBe(null)
4343
})
4444

45+
test('create from an existing vnode', () => {
46+
const vnode1 = createVNode('p', { id: 'foo' })
47+
const vnode2 = createVNode(vnode1, { class: 'bar' }, 'baz')
48+
expect(vnode2).toMatchObject({
49+
type: 'p',
50+
props: {
51+
id: 'foo',
52+
class: 'bar'
53+
},
54+
children: 'baz',
55+
shapeFlag: ShapeFlags.ELEMENT | ShapeFlags.TEXT_CHILDREN
56+
})
57+
})
58+
4559
test('vnode keys', () => {
4660
for (const key of ['', 'a', 0, 1, NaN]) {
4761
expect(createVNode('div', { key }).key).toBe(key)

packages/runtime-core/src/vnode.ts

+12-3
Original file line numberDiff line numberDiff line change
@@ -290,7 +290,7 @@ export const createVNode = (__DEV__
290290
: _createVNode) as typeof _createVNode
291291

292292
function _createVNode(
293-
type: VNodeTypes | ClassComponent | typeof NULL_DYNAMIC_COMPONENT,
293+
type: VNode | VNodeTypes | ClassComponent | typeof NULL_DYNAMIC_COMPONENT,
294294
props: (Data & VNodeProps) | null = null,
295295
children: unknown = null,
296296
patchFlag: number = 0,
@@ -304,6 +304,10 @@ function _createVNode(
304304
type = Comment
305305
}
306306

307+
if (isVNode(type)) {
308+
return cloneVNode(type, props, children)
309+
}
310+
307311
// class component normalization.
308312
if (isFunction(type) && '__vccOpts' in type) {
309313
type = type.__vccOpts
@@ -406,7 +410,8 @@ function _createVNode(
406410

407411
export function cloneVNode<T, U>(
408412
vnode: VNode<T, U>,
409-
extraProps?: Data & VNodeProps
413+
extraProps?: Data & VNodeProps | null,
414+
children?: unknown
410415
): VNode<T, U> {
411416
const props = extraProps
412417
? vnode.props
@@ -415,7 +420,7 @@ export function cloneVNode<T, U>(
415420
: vnode.props
416421
// This is intentionally NOT using spread or extend to avoid the runtime
417422
// key enumeration cost.
418-
return {
423+
const cloned: VNode<T, U> = {
419424
__v_isVNode: true,
420425
__v_skip: true,
421426
type: vnode.type,
@@ -452,6 +457,10 @@ export function cloneVNode<T, U>(
452457
el: vnode.el,
453458
anchor: vnode.anchor
454459
}
460+
if (children) {
461+
normalizeChildren(cloned, children)
462+
}
463+
return cloned
455464
}
456465

457466
/**

0 commit comments

Comments
 (0)