]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
wip: $data should only expose properties from data()
authorEvan You <yyx990803@gmail.com>
Fri, 6 Sep 2019 00:36:35 +0000 (20:36 -0400)
committerEvan You <yyx990803@gmail.com>
Fri, 6 Sep 2019 00:36:35 +0000 (20:36 -0400)
packages/runtime-core/src/apiOptions.ts
packages/runtime-core/src/component.ts
packages/runtime-core/src/componentProxy.ts
packages/runtime-core/src/createRenderer.ts

index 11f5df98f930fba548ae72de0fa089311c24f3b4..fb61b96adc75f13dd5206472e840f0b3659b56df 100644 (file)
@@ -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)
         }
       }
     }
index 2c24269255a1ee25f6f1231b098b5c17a3381954..3583d70f5834d7e1a959e83f2234c47d0008661b 100644 (file)
@@ -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<P = Data, D = Data> = {
+export interface ComponentInstance {
   type: FunctionalComponent | ComponentOptions
   parent: ComponentInstance | null
   appContext: AppContext
@@ -169,12 +171,16 @@ export type ComponentInstance<P = Data, D = Data> = {
   directives: Record<string, Directive>
 
   // 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<P = Data, D = Data> = {
   [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
 }
index 891490d68bfa9498924042a7e196d2f9d15c71bb..019e420453af655cc7146b3896b4a609e9c06d30 100644 (file)
@@ -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
   }
 }
index 15980b6bf348e3a1a8865fe36404e79635ffc7b8..fd0d6aa29fea1b15034529717e3da37244d40348 100644 (file)
@@ -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
       }