From 200c035862b35857736491e1cd0774b86d7f9a4d Mon Sep 17 00:00:00 2001 From: Evan You Date: Thu, 30 May 2019 16:00:42 +0800 Subject: [PATCH] wip: component update fast path --- packages/runtime-core/src/component.ts | 64 ++++++++++++++----------- packages/runtime-core/src/patchFlags.ts | 1 + packages/runtime-core/src/vnode.ts | 4 +- 3 files changed, 39 insertions(+), 30 deletions(-) diff --git a/packages/runtime-core/src/component.ts b/packages/runtime-core/src/component.ts index 8b7cea0b..6f61660e 100644 --- a/packages/runtime-core/src/component.ts +++ b/packages/runtime-core/src/component.ts @@ -3,6 +3,7 @@ import { ReactiveEffect, UnwrapValue, observable } from '@vue/observer' import { isFunction, EMPTY_OBJ } from '@vue/shared' import { RenderProxyHandlers } from './componentProxy' import { ComponentPropsOptions, PropValidator } from './componentProps' +import { PROPS, SLOTS } from './patchFlags' export type Data = { [key: string]: any } @@ -167,36 +168,43 @@ export function shouldUpdateComponent( nextVNode: VNode ): boolean { const { props: prevProps } = prevVNode - const { props: nextProps } = nextVNode - - // TODO handle slots - // If has different slots content, or has non-compiled slots, - // the child needs to be force updated. - // if ( - // prevChildFlags !== nextChildFlags || - // (nextChildFlags & ChildrenFlags.DYNAMIC_SLOTS) > 0 - // ) { - // return true - // } - - if (prevProps === nextProps) { - return false - } - if (prevProps === null) { - return nextProps !== null - } - if (nextProps === null) { - return prevProps !== null - } - const nextKeys = Object.keys(nextProps) - if (nextKeys.length !== Object.keys(prevProps).length) { - return true - } - for (let i = 0; i < nextKeys.length; i++) { - const key = nextKeys[i] - if (nextProps[key] !== prevProps[key]) { + const { props: nextProps, patchFlag } = nextVNode + if (patchFlag !== null) { + if (patchFlag & SLOTS) { + // slot content that references values that might have changed, + // e.g. in a v-for return true } + if (patchFlag & PROPS) { + const dynamicProps = nextVNode.dynamicProps as string[] + for (let i = 0; i < dynamicProps.length; i++) { + const key = dynamicProps[i] + if ((nextProps as any)[key] !== (prevProps as any)[key]) { + return true + } + } + } + } else { + // TODO handle slots + if (prevProps === nextProps) { + return false + } + if (prevProps === null) { + return nextProps !== null + } + if (nextProps === null) { + return prevProps !== null + } + const nextKeys = Object.keys(nextProps) + if (nextKeys.length !== Object.keys(prevProps).length) { + return true + } + for (let i = 0; i < nextKeys.length; i++) { + const key = nextKeys[i] + if (nextProps[key] !== prevProps[key]) { + return true + } + } } return false } diff --git a/packages/runtime-core/src/patchFlags.ts b/packages/runtime-core/src/patchFlags.ts index 5d6a0b7f..f28ffd15 100644 --- a/packages/runtime-core/src/patchFlags.ts +++ b/packages/runtime-core/src/patchFlags.ts @@ -4,3 +4,4 @@ export const STYLE = 1 << 2 export const PROPS = 1 << 3 export const KEYED = 1 << 4 export const UNKEYED = 1 << 5 +export const SLOTS = 1 << 6 // component only diff --git a/packages/runtime-core/src/vnode.ts b/packages/runtime-core/src/vnode.ts index 2b06f224..8dca305a 100644 --- a/packages/runtime-core/src/vnode.ts +++ b/packages/runtime-core/src/vnode.ts @@ -1,4 +1,4 @@ -import { isArray, isFunction, EMPTY_ARR } from '@vue/shared' +import { isArray, EMPTY_ARR } from '@vue/shared' import { ComponentInstance } from './component' import { HostNode } from './createRenderer' @@ -87,7 +87,7 @@ export function createVNode( dynamicProps, dynamicChildren: null } - if (shouldTrack && (patchFlag != null || isFunction(type))) { + if (shouldTrack && patchFlag != null) { trackDynamicNode(vnode) } return vnode