From 7eed0df3c2ffc0bf5ca6785eb13571c1382dd3ba Mon Sep 17 00:00:00 2001 From: Evan You Date: Thu, 5 Sep 2019 20:36:35 -0400 Subject: [PATCH] wip: $data should only expose properties from data() --- packages/runtime-core/src/apiOptions.ts | 22 +++++++++++------- packages/runtime-core/src/component.ts | 25 +++++++++++++-------- packages/runtime-core/src/componentProxy.ts | 17 ++++++++------ packages/runtime-core/src/createRenderer.ts | 6 ++--- 4 files changed, 43 insertions(+), 27 deletions(-) diff --git a/packages/runtime-core/src/apiOptions.ts b/packages/runtime-core/src/apiOptions.ts index 11f5df98..fb61b96a 100644 --- a/packages/runtime-core/src/apiOptions.ts +++ b/packages/runtime-core/src/apiOptions.ts @@ -112,8 +112,10 @@ export function applyOptions( options: ComponentOptions, asMixin: boolean = false ) { - const data = - instance.data === EMPTY_OBJ ? (instance.data = reactive({})) : instance.data + const renderContext = + instance.renderContext === EMPTY_OBJ + ? (instance.renderContext = reactive({})) + : instance.renderContext const ctx = instance.renderProxy as any const { // composition @@ -166,12 +168,16 @@ export function applyOptions( // state options if (dataOptions) { + const data = + instance.data === EMPTY_OBJ + ? (instance.data = reactive({})) + : instance.data extend(data, isFunction(dataOptions) ? dataOptions.call(ctx) : dataOptions) } if (computedOptions) { for (const key in computedOptions) { const opt = (computedOptions as ComputedOptions)[key] - data[key] = isFunction(opt) + renderContext[key] = isFunction(opt) ? computed(opt.bind(ctx)) : computed({ get: opt.get.bind(ctx), @@ -181,7 +187,7 @@ export function applyOptions( } if (methods) { for (const key in methods) { - data[key] = (methods as MethodOptions)[key].bind(ctx) + renderContext[key] = (methods as MethodOptions)[key].bind(ctx) } } if (watchOptions) { @@ -189,7 +195,7 @@ export function applyOptions( const raw = watchOptions[key] const getter = () => ctx[key] if (isString(raw)) { - const handler = data[raw] + const handler = renderContext[raw] if (isFunction(handler)) { watch(getter, handler as any) } else if (__DEV__) { @@ -217,15 +223,15 @@ export function applyOptions( if (isArray(injectOptions)) { for (let i = 0; i < injectOptions.length; i++) { const key = injectOptions[i] - data[key] = inject(key) + renderContext[key] = inject(key) } } else { for (const key in injectOptions) { const opt = injectOptions[key] if (isObject(opt)) { - data[key] = inject(opt.from, opt.default) + renderContext[key] = inject(opt.from, opt.default) } else { - data[key] = inject(opt) + renderContext[key] = inject(opt) } } } diff --git a/packages/runtime-core/src/component.ts b/packages/runtime-core/src/component.ts index 2c242692..3583d70f 100644 --- a/packages/runtime-core/src/component.ts +++ b/packages/runtime-core/src/component.ts @@ -144,15 +144,17 @@ export const enum LifecycleHooks { ERROR_CAPTURED = 'ec' } +type Emit = ((event: string, ...args: unknown[]) => void) + interface SetupContext { attrs: Data slots: Slots - emit: ((event: string, ...args: unknown[]) => void) + emit: Emit } type RenderFunction = () => VNodeChild -export type ComponentInstance

= { +export interface ComponentInstance { type: FunctionalComponent | ComponentOptions parent: ComponentInstance | null appContext: AppContext @@ -169,12 +171,16 @@ export type ComponentInstance

= { directives: Record // the rest are only for stateful components - data: D - props: P + renderContext: Data + data: Data + props: Data + attrs: Data + slots: Slots renderProxy: ComponentRenderProxy | null - propsProxy: P | null + propsProxy: Data | null setupContext: SetupContext | null refs: Data + emit: Emit // user namespace user: { [key: string]: any } @@ -193,7 +199,7 @@ export type ComponentInstance

= { [LifecycleHooks.ACTIVATED]: LifecycleHook [LifecycleHooks.DEACTIVATED]: LifecycleHook [LifecycleHooks.ERROR_CAPTURED]: LifecycleHook -} & SetupContext +} // createComponent // overload 1: direct setup function @@ -287,6 +293,7 @@ export function createComponentInstance( provides: parent ? parent.provides : Object.create(appContext.provides), // setup context properties + renderContext: EMPTY_OBJ, data: EMPTY_OBJ, props: EMPTY_OBJ, attrs: EMPTY_OBJ, @@ -397,7 +404,7 @@ export function setupStatefulComponent(instance: ComponentInstance) { // setup returned bindings. // assuming a render function compiled from template is present. if (isObject(setupResult)) { - instance.data = reactive(setupResult) + instance.renderContext = reactive(setupResult) } else if (__DEV__ && setupResult !== undefined) { warn( `setup() should return an object. Received: ${ @@ -420,8 +427,8 @@ export function setupStatefulComponent(instance: ComponentInstance) { if (__FEATURE_OPTIONS__) { applyOptions(instance, Component) } - if (instance.data === EMPTY_OBJ) { - instance.data = reactive({}) + if (instance.renderContext === EMPTY_OBJ) { + instance.renderContext = reactive({}) } currentInstance = null } diff --git a/packages/runtime-core/src/componentProxy.ts b/packages/runtime-core/src/componentProxy.ts index 891490d6..019e4204 100644 --- a/packages/runtime-core/src/componentProxy.ts +++ b/packages/runtime-core/src/componentProxy.ts @@ -1,12 +1,15 @@ import { ComponentInstance } from './component' import { nextTick } from './scheduler' import { instanceWatch } from './apiWatch' +import { EMPTY_OBJ } from '@vue/shared' export const RenderProxyHandlers = { get(target: ComponentInstance, key: string) { - const { data, props, propsProxy } = target - if (data.hasOwnProperty(key)) { + const { renderContext, data, props, propsProxy } = target + if (data !== EMPTY_OBJ && data.hasOwnProperty(key)) { return data[key] + } else if (renderContext.hasOwnProperty(key)) { + return renderContext[key] } else if (props.hasOwnProperty(key)) { // return the value from propsProxy for ref unwrapping and readonly return (propsProxy as any)[key] @@ -31,7 +34,6 @@ export const RenderProxyHandlers = { case '$el': return target.vnode.el case '$options': - // TODO handle merging return target.type default: // methods are only exposed when options are supported @@ -50,10 +52,11 @@ export const RenderProxyHandlers = { } }, set(target: ComponentInstance, key: string, value: any): boolean { - const { data } = target - if (data.hasOwnProperty(key)) { + const { data, renderContext } = target + if (data !== EMPTY_OBJ && data.hasOwnProperty(key)) { data[key] = value - return true + } else if (renderContext.hasOwnProperty(key)) { + renderContext[key] = value } else if (key[0] === '$' && key.slice(1) in target) { // TODO warn attempt of mutating public property return false @@ -62,7 +65,7 @@ export const RenderProxyHandlers = { return false } else { target.user[key] = value - return true } + return true } } diff --git a/packages/runtime-core/src/createRenderer.ts b/packages/runtime-core/src/createRenderer.ts index 15980b6b..fd0d6aa2 100644 --- a/packages/runtime-core/src/createRenderer.ts +++ b/packages/runtime-core/src/createRenderer.ts @@ -1127,13 +1127,13 @@ export function createRenderer(options: RendererOptions): RootRenderFunction { value: HostNode | ComponentInstance | null ) { const refs = parent.refs === EMPTY_OBJ ? (parent.refs = {}) : parent.refs - const rawData = toRaw(parent.data) + const renderContext = toRaw(parent.renderContext) // unset old ref if (oldRef !== null && oldRef !== ref) { if (isString(oldRef)) { refs[oldRef] = null - const oldSetupRef = rawData[oldRef] + const oldSetupRef = renderContext[oldRef] if (isRef(oldSetupRef)) { oldSetupRef.value = null } @@ -1143,7 +1143,7 @@ export function createRenderer(options: RendererOptions): RootRenderFunction { } if (isString(ref)) { - const setupRef = rawData[ref] + const setupRef = renderContext[ref] if (isRef(setupRef)) { setupRef.value = value }