Просмотр исходного кода

wip: always track component nodes

Evan You 7 лет назад
Родитель
Сommit
05556eacb2

+ 3 - 2
packages/runtime-core/src/component.ts

@@ -163,7 +163,8 @@ export function renderComponentRoot(instance: ComponentInstance): VNode {
 
 export function shouldUpdateComponent(
   prevVNode: VNode,
-  nextVNode: VNode
+  nextVNode: VNode,
+  optimized?: boolean
 ): boolean {
   const { props: prevProps, children: prevChildren } = prevVNode
   const { props: nextProps, children: nextChildren, patchFlag } = nextVNode
@@ -185,7 +186,7 @@ export function shouldUpdateComponent(
         }
       }
     }
-  } else {
+  } else if (!optimized) {
     // this path is only taken by manually written render functions
     // so presence of any children leads to a forced update
     if (prevChildren != null || nextChildren != null) {

+ 5 - 3
packages/runtime-core/src/createRenderer.ts

@@ -139,7 +139,7 @@ export function createRenderer(options: RendererOptions) {
             // TODO warn invalid node type
             debugger
           }
-          processComponent(n1, n2, container, anchor)
+          processComponent(n1, n2, container, anchor, optimized)
         }
         break
     }
@@ -426,16 +426,18 @@ export function createRenderer(options: RendererOptions) {
     n1: VNode | null,
     n2: VNode,
     container: HostNode,
-    anchor?: HostNode
+    anchor?: HostNode,
+    optimized?: boolean
   ) {
     if (n1 == null) {
       mountComponent(n2, container, anchor)
     } else {
       const instance = (n2.component = n1.component) as ComponentInstance
-      if (shouldUpdateComponent(n1, n2)) {
+      if (shouldUpdateComponent(n1, n2, optimized)) {
         instance.next = n2
         instance.update()
       } else {
+        n2.component = n1.component
         n2.el = n1.el
       }
     }

+ 3 - 5
packages/runtime-core/src/index.ts

@@ -3,15 +3,13 @@ export {
   openBlock,
   createBlock,
   createVNode,
+  Text,
+  Empty,
   Fragment,
   Portal
 } from './vnode'
 
-export {
-  ComponentOptions,
-  FunctionalComponent,
-  createComponent
-} from './component'
+export { FunctionalComponent, createComponent } from './component'
 
 export { Slot, Slots } from './componentSlots'
 

+ 10 - 4
packages/runtime-core/src/vnode.ts

@@ -1,4 +1,4 @@
-import { isArray, isFunction, isString, EMPTY_ARR } from '@vue/shared'
+import { isArray, isFunction, isString, isObject, EMPTY_ARR } from '@vue/shared'
 import { ComponentInstance } from './component'
 import { HostNode } from './createRenderer'
 import { RawSlots } from './componentSlots'
@@ -85,14 +85,14 @@ export function createBlock(
 
 export function createVNode(
   type: VNodeTypes,
-  props: { [key: string]: any } | null = null,
+  props: { [key: string]: any } | null | 0 = null,
   children: any = null,
   patchFlag: number | null = null,
   dynamicProps: string[] | null = null
 ): VNode {
   const vnode: VNode = {
     type,
-    props,
+    props: props || null,
     key: props && props.key,
     children: normalizeChildren(children),
     component: null,
@@ -104,7 +104,13 @@ export function createVNode(
     dynamicChildren: null
   }
   // presence of a patch flag indicates this node is dynamic
-  if (shouldTrack && patchFlag != null) {
+  // component nodes also should always be tracked, because even if the
+  // component doesn't need to update, it needs to persist the instance on to
+  // the next vnode so that it can be properly unmounted later.
+  if (
+    shouldTrack &&
+    (patchFlag != null || isObject(type) || isFunction(type))
+  ) {
     trackDynamicNode(vnode)
   }
   return vnode