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=""/>`
This commit is contained in:
Evan You 2020-07-01 19:48:01 -04:00
parent 359b4a30ca
commit c9629f2692
2 changed files with 26 additions and 3 deletions

View File

@ -42,6 +42,20 @@ describe('vnode', () => {
expect(vnode.props).toBe(null) expect(vnode.props).toBe(null)
}) })
test('create from an existing vnode', () => {
const vnode1 = createVNode('p', { id: 'foo' })
const vnode2 = createVNode(vnode1, { class: 'bar' }, 'baz')
expect(vnode2).toMatchObject({
type: 'p',
props: {
id: 'foo',
class: 'bar'
},
children: 'baz',
shapeFlag: ShapeFlags.ELEMENT | ShapeFlags.TEXT_CHILDREN
})
})
test('vnode keys', () => { test('vnode keys', () => {
for (const key of ['', 'a', 0, 1, NaN]) { for (const key of ['', 'a', 0, 1, NaN]) {
expect(createVNode('div', { key }).key).toBe(key) expect(createVNode('div', { key }).key).toBe(key)

View File

@ -290,7 +290,7 @@ export const createVNode = (__DEV__
: _createVNode) as typeof _createVNode : _createVNode) as typeof _createVNode
function _createVNode( function _createVNode(
type: VNodeTypes | ClassComponent | typeof NULL_DYNAMIC_COMPONENT, type: VNode | VNodeTypes | ClassComponent | typeof NULL_DYNAMIC_COMPONENT,
props: (Data & VNodeProps) | null = null, props: (Data & VNodeProps) | null = null,
children: unknown = null, children: unknown = null,
patchFlag: number = 0, patchFlag: number = 0,
@ -304,6 +304,10 @@ function _createVNode(
type = Comment type = Comment
} }
if (isVNode(type)) {
return cloneVNode(type, props, children)
}
// class component normalization. // class component normalization.
if (isFunction(type) && '__vccOpts' in type) { if (isFunction(type) && '__vccOpts' in type) {
type = type.__vccOpts type = type.__vccOpts
@ -406,7 +410,8 @@ function _createVNode(
export function cloneVNode<T, U>( export function cloneVNode<T, U>(
vnode: VNode<T, U>, vnode: VNode<T, U>,
extraProps?: Data & VNodeProps extraProps?: Data & VNodeProps | null,
children?: unknown
): VNode<T, U> { ): VNode<T, U> {
const props = extraProps const props = extraProps
? vnode.props ? vnode.props
@ -415,7 +420,7 @@ export function cloneVNode<T, U>(
: vnode.props : vnode.props
// This is intentionally NOT using spread or extend to avoid the runtime // This is intentionally NOT using spread or extend to avoid the runtime
// key enumeration cost. // key enumeration cost.
return { const cloned: VNode<T, U> = {
__v_isVNode: true, __v_isVNode: true,
__v_skip: true, __v_skip: true,
type: vnode.type, type: vnode.type,
@ -452,6 +457,10 @@ export function cloneVNode<T, U>(
el: vnode.el, el: vnode.el,
anchor: vnode.anchor anchor: vnode.anchor
} }
if (children) {
normalizeChildren(cloned, children)
}
return cloned
} }
/** /**