]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
wip: render proxy
authorEvan You <yyx990803@gmail.com>
Wed, 29 May 2019 05:43:46 +0000 (13:43 +0800)
committerEvan You <yyx990803@gmail.com>
Wed, 29 May 2019 05:43:46 +0000 (13:43 +0800)
packages/runtime-core/src/component.ts
packages/runtime-core/src/componentProxy.ts
packages/runtime-core/src/createRenderer.ts

index b2a980fc2889ef8a5e1483e4ffc20bdf641f99c3..a1728939266e12880493c781e568d94403d9a03d 100644 (file)
@@ -1,5 +1,5 @@
 import { VNode, normalizeVNode, VNodeChild } from './vnode'
-import { ReactiveEffect } from '@vue/observer'
+import { ReactiveEffect, observable } from '@vue/observer'
 import { isFunction, EMPTY_OBJ } from '@vue/shared'
 import { RenderProxyHandlers } from './componentProxy'
 import { ComponentPropsOptions, PropValidator } from './componentProps'
@@ -30,6 +30,9 @@ export interface ComponentPublicProperties<P = Data, S = Data> {
   // TODO
   $refs: Data
   $slots: Data
+
+  $root: ComponentInstance | null
+  $parent: ComponentInstance | null
 }
 
 export interface ComponentOptions<
@@ -147,7 +150,7 @@ export function setupStatefulComponent(instance: ComponentInstance) {
   if (Component.setup) {
     currentInstance = instance
     // TODO should pass reactive props here
-    instance.state = Component.setup.call(proxy, instance.props)
+    instance.state = observable(Component.setup.call(proxy, instance.props))
     currentInstance = null
   }
 }
index a447b61d236231a76441364459f38e3699fefc80..0974e6cbabf6fb308ef012158559885117f14fdc 100644 (file)
@@ -1 +1,55 @@
-export const RenderProxyHandlers = {}
+import { ComponentInstance } from './component'
+import { isObservable, unwrap } from '@vue/observer'
+
+// TODO use proper implementation
+function isValue(binding: any) {
+  return isObservable(binding) && unwrap(binding).hasOwnProperty('value')
+}
+
+export const RenderProxyHandlers = {
+  get(target: ComponentInstance, key: string) {
+    const { state, props } = target
+    if (state.hasOwnProperty(key)) {
+      const value = state[key]
+      return isValue(value) ? value.value : value
+    } else if (props.hasOwnProperty(key)) {
+      return props[key]
+    } else {
+      switch (key) {
+        case '$state':
+          return target.state
+        case '$props':
+          return target.props
+        case '$attrs':
+          return target.attrs
+        case '$slots':
+          return target.slots
+        case '$refs':
+          return target.refs
+        default:
+          break
+      }
+    }
+  },
+  set(target: ComponentInstance, key: string, value: any): boolean {
+    const { state } = target
+    if (state.hasOwnProperty(key)) {
+      const binding = state[key]
+      if (isValue(binding)) {
+        binding.value = value
+      } else {
+        state[key] = value
+      }
+      return true
+    } else {
+      if (__DEV__) {
+        if (key[0] === '$') {
+          // TODO warn attempt of mutating public property
+        } else if (target.props.hasOwnProperty(key)) {
+          // TODO warn attempt of mutating prop
+        }
+      }
+    }
+    return false
+  }
+}
index 52d0c1df843595f9143089c13efb6f9b51ae68c1..2f433290bfcb9b7839327605f9bd396f8beca2f2 100644 (file)
@@ -389,13 +389,16 @@ export function createRenderer(options: RendererOptions) {
           queuePostFlushCb(instance.m)
         }
       } else {
-        // this is triggered by processComponent with `next` already set
+        // component update
+        // This is triggered by mutation of component's own state (next: null)
+        // OR parent calling processComponent (next: VNode)
         const { next } = instance
         if (next != null) {
           next.component = instance
           instance.vnode = next
           instance.next = null
           resolveProps(instance, next.props, Component.props)
+          // TODO slots
         }
         const prevTree = instance.subTree
         const nextTree = (instance.subTree = renderComponentRoot(instance))
@@ -738,8 +741,14 @@ export function createRenderer(options: RendererOptions) {
       : getNextHostNode(vnode.component.subTree)
   }
 
-  return function render(vnode: VNode, dom: HostNode): VNode {
-    patch(dom._vnode, vnode, dom)
+  return function render(vnode: VNode | null, dom: HostNode): VNode | null {
+    if (vnode == null) {
+      if (dom._vnode) {
+        unmount(dom._vnode, true)
+      }
+    } else {
+      patch(dom._vnode, vnode, dom)
+    }
     flushPostFlushCbs()
     return (dom._vnode = vnode)
   }