wip: render proxy

This commit is contained in:
Evan You 2019-05-29 13:43:46 +08:00
parent 6ceb732114
commit 178c7c827e
3 changed files with 72 additions and 6 deletions

View 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
}
}

View 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
}
}

View 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)
}