From 6390ddfb7d0ed83ac4bae15d0497cba4de3e1972 Mon Sep 17 00:00:00 2001 From: Evan You Date: Tue, 21 Jul 2020 12:35:34 -0400 Subject: [PATCH] fix(runtime-core): do not use bail patchFlag on cloned vnodes fix #1665 - cloned vnodes with extra props will receive only the full props flag - this commit affects `cloneVNode` behavior when used in manual render functions. - ok for normal elements since elements only use patchFlags for own props optimization - full props flag is skipped for fragments because fragments use patchFlags only for children optimization - this also affects `shouldUpdateComponent` where it should now only respect patchFlags in optimized mode, since component vnodes use the patchFlag for both props and slots optimization checks. --- .../runtime-core/src/componentRenderUtils.ts | 4 +-- packages/runtime-core/src/vnode.ts | 26 ++++++++----------- 2 files changed, 13 insertions(+), 17 deletions(-) diff --git a/packages/runtime-core/src/componentRenderUtils.ts b/packages/runtime-core/src/componentRenderUtils.ts index 54fa4b3f..bd1ce451 100644 --- a/packages/runtime-core/src/componentRenderUtils.ts +++ b/packages/runtime-core/src/componentRenderUtils.ts @@ -279,7 +279,7 @@ export function shouldUpdateComponent( return true } - if (patchFlag > 0) { + if (optimized && patchFlag > 0) { if (patchFlag & PatchFlags.DYNAMIC_SLOTS) { // slot content that references values that might have changed, // e.g. in a v-for @@ -300,7 +300,7 @@ export function shouldUpdateComponent( } } } - } else if (!optimized) { + } else { // this path is only taken by manually written render functions // so presence of any children leads to a forced update if (prevChildren || nextChildren) { diff --git a/packages/runtime-core/src/vnode.ts b/packages/runtime-core/src/vnode.ts index 5cde39f8..5cd08bc1 100644 --- a/packages/runtime-core/src/vnode.ts +++ b/packages/runtime-core/src/vnode.ts @@ -310,7 +310,11 @@ function _createVNode( } if (isVNode(type)) { - return cloneVNode(type, props, children) + const cloned = cloneVNode(type, props) + if (children) { + normalizeChildren(cloned, children) + } + return cloned } // class component normalization. @@ -420,8 +424,7 @@ function _createVNode( export function cloneVNode( vnode: VNode, - extraProps?: Data & VNodeProps | null, - children?: unknown + extraProps?: Data & VNodeProps | null ): VNode { const props = extraProps ? vnode.props @@ -430,7 +433,7 @@ export function cloneVNode( : vnode.props // This is intentionally NOT using spread or extend to avoid the runtime // key enumeration cost. - const cloned: VNode = { + return { __v_isVNode: true, __v_skip: true, type: vnode.type, @@ -444,14 +447,11 @@ export function cloneVNode( staticCount: vnode.staticCount, 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 bail out of optimized mode. - // however we don't want block nodes to de-opt their children, so if the - // vnode is a block node, we only add the FULL_PROPS flag to it. - patchFlag: extraProps - ? vnode.dynamicChildren + // existing patch flag to be reliable and need to add the FULL_PROPS flag. + patchFlag: + extraProps && vnode.type !== Fragment ? vnode.patchFlag | PatchFlags.FULL_PROPS - : PatchFlags.BAIL - : vnode.patchFlag, + : vnode.patchFlag, dynamicProps: vnode.dynamicProps, dynamicChildren: vnode.dynamicChildren, appContext: vnode.appContext, @@ -467,10 +467,6 @@ export function cloneVNode( el: vnode.el, anchor: vnode.anchor } - if (children) { - normalizeChildren(cloned, children) - } - return cloned } /**