diff --git a/packages/runtime-core/__tests__/rendererAttrsFallthrough.spec.ts b/packages/runtime-core/__tests__/rendererAttrsFallthrough.spec.ts index d8452db58f9..ab18c842601 100644 --- a/packages/runtime-core/__tests__/rendererAttrsFallthrough.spec.ts +++ b/packages/runtime-core/__tests__/rendererAttrsFallthrough.spec.ts @@ -10,7 +10,8 @@ import { openBlock, createBlock, FunctionalComponent, - createCommentVNode + createCommentVNode, + Fragment } from '@vue/runtime-dom' import { mockWarn } from '@vue/shared' @@ -573,12 +574,15 @@ describe('attribute fallthrough', () => { } const Child = { - setup(props: any) { - return () => [ - createCommentVNode('hello'), - h('button'), - createCommentVNode('world') - ] + setup() { + return () => ( + openBlock(), + createBlock(Fragment, null, [ + createCommentVNode('hello'), + h('button'), + createCommentVNode('world') + ]) + ) } } diff --git a/packages/runtime-core/src/componentRenderUtils.ts b/packages/runtime-core/src/componentRenderUtils.ts index bd1ce451df0..dad54bcadca 100644 --- a/packages/runtime-core/src/componentRenderUtils.ts +++ b/packages/runtime-core/src/componentRenderUtils.ts @@ -215,6 +215,9 @@ export function renderComponentRoot( return result } +/** + * dev only + */ const getChildRoot = ( vnode: VNode ): [VNode, ((root: VNode) => void) | undefined] => { @@ -231,12 +234,14 @@ const getChildRoot = ( } const childRoot = children[0] const index = rawChildren.indexOf(childRoot) - const dynamicIndex = dynamicChildren - ? dynamicChildren.indexOf(childRoot) - : null + const dynamicIndex = dynamicChildren ? dynamicChildren.indexOf(childRoot) : -1 const setRoot = (updatedRoot: VNode) => { rawChildren[index] = updatedRoot - if (dynamicIndex !== null) dynamicChildren[dynamicIndex] = updatedRoot + if (dynamicIndex > -1) { + dynamicChildren[dynamicIndex] = updatedRoot + } else if (dynamicChildren && updatedRoot.patchFlag > 0) { + dynamicChildren.push(updatedRoot) + } } return [normalizeVNode(childRoot), setRoot] } diff --git a/packages/runtime-core/src/vnode.ts b/packages/runtime-core/src/vnode.ts index 5cd08bc15c9..ba0a4cafb52 100644 --- a/packages/runtime-core/src/vnode.ts +++ b/packages/runtime-core/src/vnode.ts @@ -426,19 +426,20 @@ export function cloneVNode( vnode: VNode, extraProps?: Data & VNodeProps | null ): VNode { - const props = extraProps - ? vnode.props - ? mergeProps(vnode.props, extraProps) - : extend({}, extraProps) - : vnode.props // This is intentionally NOT using spread or extend to avoid the runtime // key enumeration cost. + const { props, patchFlag } = vnode + const mergedProps = extraProps + ? props + ? mergeProps(props, extraProps) + : extend({}, extraProps) + : props return { __v_isVNode: true, __v_skip: true, type: vnode.type, - props, - key: props && normalizeKey(props), + props: mergedProps, + key: mergedProps && normalizeKey(mergedProps), ref: extraProps && extraProps.ref ? normalizeRef(extraProps) : vnode.ref, scopeId: vnode.scopeId, children: vnode.children, @@ -448,10 +449,14 @@ export function cloneVNode( shapeFlag: vnode.shapeFlag, // if the vnode is cloned with extra props, we can no longer assume its // existing patch flag to be reliable and need to add the FULL_PROPS flag. + // note: perserve flag for fragments since they use the flag for children + // fast paths only. patchFlag: extraProps && vnode.type !== Fragment - ? vnode.patchFlag | PatchFlags.FULL_PROPS - : vnode.patchFlag, + ? patchFlag === -1 // hoisted node + ? PatchFlags.FULL_PROPS + : patchFlag | PatchFlags.FULL_PROPS + : patchFlag, dynamicProps: vnode.dynamicProps, dynamicChildren: vnode.dynamicChildren, appContext: vnode.appContext,