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 { VNode, normalizeVNode, VNodeChild } from './vnode'
import { ReactiveEffect } from '@vue/observer' import { ReactiveEffect, observable } from '@vue/observer'
import { isFunction, EMPTY_OBJ } from '@vue/shared' import { isFunction, EMPTY_OBJ } from '@vue/shared'
import { RenderProxyHandlers } from './componentProxy' import { RenderProxyHandlers } from './componentProxy'
import { ComponentPropsOptions, PropValidator } from './componentProps' import { ComponentPropsOptions, PropValidator } from './componentProps'
@ -30,6 +30,9 @@ export interface ComponentPublicProperties<P = Data, S = Data> {
// TODO // TODO
$refs: Data $refs: Data
$slots: Data $slots: Data
$root: ComponentInstance | null
$parent: ComponentInstance | null
} }
export interface ComponentOptions< export interface ComponentOptions<
@ -147,7 +150,7 @@ export function setupStatefulComponent(instance: ComponentInstance) {
if (Component.setup) { if (Component.setup) {
currentInstance = instance currentInstance = instance
// TODO should pass reactive props here // 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 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) queuePostFlushCb(instance.m)
} }
} else { } 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 const { next } = instance
if (next != null) { if (next != null) {
next.component = instance next.component = instance
instance.vnode = next instance.vnode = next
instance.next = null instance.next = null
resolveProps(instance, next.props, Component.props) resolveProps(instance, next.props, Component.props)
// TODO slots
} }
const prevTree = instance.subTree const prevTree = instance.subTree
const nextTree = (instance.subTree = renderComponentRoot(instance)) const nextTree = (instance.subTree = renderComponentRoot(instance))
@ -738,8 +741,14 @@ export function createRenderer(options: RendererOptions) {
: getNextHostNode(vnode.component.subTree) : getNextHostNode(vnode.component.subTree)
} }
return function render(vnode: VNode, dom: HostNode): VNode { return function render(vnode: VNode | null, dom: HostNode): VNode | null {
patch(dom._vnode, vnode, dom) if (vnode == null) {
if (dom._vnode) {
unmount(dom._vnode, true)
}
} else {
patch(dom._vnode, vnode, dom)
}
flushPostFlushCbs() flushPostFlushCbs()
return (dom._vnode = vnode) return (dom._vnode = vnode)
} }