From b2662a62c517b03694fd515217b12b1e564d03d3 Mon Sep 17 00:00:00 2001 From: Evan You Date: Thu, 16 Apr 2020 11:50:33 -0400 Subject: [PATCH] wip: separate setupState --- .../__tests__/componentProxy.spec.ts | 4 +- packages/runtime-core/src/component.ts | 21 +++--- packages/runtime-core/src/componentProxy.ts | 70 ++++++++++++------- packages/runtime-core/src/renderer.ts | 10 +-- 4 files changed, 64 insertions(+), 41 deletions(-) diff --git a/packages/runtime-core/__tests__/componentProxy.spec.ts b/packages/runtime-core/__tests__/componentProxy.spec.ts index cd03ce70..8b88ca9b 100644 --- a/packages/runtime-core/__tests__/componentProxy.spec.ts +++ b/packages/runtime-core/__tests__/componentProxy.spec.ts @@ -35,7 +35,7 @@ describe('component: proxy', () => { expect(instance!.data.foo).toBe(2) }) - test('renderContext', () => { + test('setupState', () => { let instance: ComponentInternalInstance let instanceProxy: any const Comp = { @@ -55,7 +55,7 @@ describe('component: proxy', () => { render(h(Comp), nodeOps.createElement('div')) expect(instanceProxy.foo).toBe(1) instanceProxy.foo = 2 - expect(instance!.renderContext.foo).toBe(2) + expect(instance!.setupState.foo).toBe(2) }) test('should not expose non-declared props', () => { diff --git a/packages/runtime-core/src/component.ts b/packages/runtime-core/src/component.ts index da31dfda..53ee3e41 100644 --- a/packages/runtime-core/src/component.ts +++ b/packages/runtime-core/src/component.ts @@ -13,7 +13,7 @@ import { RuntimeCompiledPublicInstanceProxyHandlers, createDevProxyTarget, exposePropsOnDevProxyTarget, - exposeRenderContextOnDevProxyTarget + exposeSetupStateOnDevProxyTarget } from './componentProxy' import { ComponentPropsOptions, initProps } from './componentProps' import { Slots, initSlots, InternalSlots } from './componentSlots' @@ -143,6 +143,13 @@ export interface ComponentInternalInstance { attrs: Data slots: InternalSlots proxy: ComponentPublicInstance | null + refs: Data + emit: EmitFn + + // setup + setupState: Data + setupContext: SetupContext | null + // The target object for the public instance proxy. In dev mode, we also // define getters for all known instance properties on it so it can be // properly inspected in the console. These getters are skipped in prod mode @@ -152,9 +159,6 @@ export interface ComponentInternalInstance { // alternative proxy used only for runtime-compiled render functions using // `with` block withProxy: ComponentPublicInstance | null - setupContext: SetupContext | null - refs: Data - emit: EmitFn // suspense related suspense: SuspenseBoundary | null @@ -209,19 +213,20 @@ export function createComponentInstance( proxy: null, proxyTarget: null!, // to be immediately set withProxy: null, - setupContext: null, effects: null, provides: parent ? parent.provides : Object.create(appContext.provides), accessCache: null!, renderCache: [], - // setup context properties + // state renderContext: EMPTY_OBJ, data: EMPTY_OBJ, props: EMPTY_OBJ, attrs: EMPTY_OBJ, slots: EMPTY_OBJ, refs: EMPTY_OBJ, + setupState: EMPTY_OBJ, + setupContext: null, // per-instance asset storage (mutable during options resolution) components: Object.create(appContext.components), @@ -392,9 +397,9 @@ export function handleSetupResult( } // setup returned bindings. // assuming a render function compiled from template is present. - instance.renderContext = reactive(setupResult) + instance.setupState = reactive(setupResult) if (__DEV__) { - exposeRenderContextOnDevProxyTarget(instance) + exposeSetupStateOnDevProxyTarget(instance) } } else if (__DEV__ && setupResult !== undefined) { warn( diff --git a/packages/runtime-core/src/componentProxy.ts b/packages/runtime-core/src/componentProxy.ts index 13954b40..d8f97c4b 100644 --- a/packages/runtime-core/src/componentProxy.ts +++ b/packages/runtime-core/src/componentProxy.ts @@ -76,9 +76,10 @@ const publicPropertiesMap: Record< } const enum AccessTypes { + SETUP, DATA, - CONTEXT, PROPS, + CONTEXT, OTHER } @@ -91,6 +92,7 @@ export const PublicInstanceProxyHandlers: ProxyHandler = { get({ _: instance }: ComponentPublicProxyTarget, key: string) { const { renderContext, + setupState, data, props, accessCache, @@ -109,6 +111,8 @@ export const PublicInstanceProxyHandlers: ProxyHandler = { const n = accessCache![key] if (n !== undefined) { switch (n) { + case AccessTypes.SETUP: + return setupState[key] case AccessTypes.DATA: return data[key] case AccessTypes.CONTEXT: @@ -117,22 +121,25 @@ export const PublicInstanceProxyHandlers: ProxyHandler = { return props![key] // default: just fallthrough } + } else if (setupState !== EMPTY_OBJ && hasOwn(setupState, key)) { + accessCache![key] = AccessTypes.SETUP + return setupState[key] } else if (data !== EMPTY_OBJ && hasOwn(data, key)) { accessCache![key] = AccessTypes.DATA return data[key] + } else if ( + // only cache other properties when instance has declared (thus stable) + // props + type.props && + hasOwn(normalizePropsOptions(type.props)[0]!, key) + ) { + accessCache![key] = AccessTypes.PROPS + return props![key] } else if (renderContext !== EMPTY_OBJ && hasOwn(renderContext, key)) { accessCache![key] = AccessTypes.CONTEXT return renderContext[key] - } else if (type.props) { - // only cache other properties when instance has declared (thus stable) - // props - if (hasOwn(normalizePropsOptions(type.props)[0]!, key)) { - accessCache![key] = AccessTypes.PROPS - // return the value from propsProxy for ref unwrapping and readonly - return props![key] - } else { - accessCache![key] = AccessTypes.OTHER - } + } else { + accessCache![key] = AccessTypes.OTHER } } @@ -170,9 +177,18 @@ export const PublicInstanceProxyHandlers: ProxyHandler = { key: string, value: any ): boolean { - const { data, renderContext } = instance - if (data !== EMPTY_OBJ && hasOwn(data, key)) { + const { data, setupState, renderContext } = instance + if (setupState !== EMPTY_OBJ && hasOwn(setupState, key)) { + setupState[key] = value + } else if (data !== EMPTY_OBJ && hasOwn(data, key)) { data[key] = value + } else if (key in instance.props) { + __DEV__ && + warn( + `Attempting to mutate prop "${key}". Props are readonly.`, + instance + ) + return false } else if (hasOwn(renderContext, key)) { renderContext[key] = value } else if (key[0] === '$' && key.slice(1) in instance) { @@ -183,13 +199,6 @@ export const PublicInstanceProxyHandlers: ProxyHandler = { instance ) return false - } else if (key in instance.props) { - __DEV__ && - warn( - `Attempting to mutate prop "${key}". Props are readonly.`, - instance - ) - return false } else { if (__DEV__ && key in instance.appContext.config.globalProperties) { Object.defineProperty(instance.proxyTarget, key, { @@ -206,15 +215,24 @@ export const PublicInstanceProxyHandlers: ProxyHandler = { has( { - _: { data, accessCache, renderContext, type, proxyTarget, appContext } + _: { + data, + setupState, + accessCache, + renderContext, + type, + proxyTarget, + appContext + } }: ComponentPublicProxyTarget, key: string ) { return ( accessCache![key] !== undefined || (data !== EMPTY_OBJ && hasOwn(data, key)) || - hasOwn(renderContext, key) || + (setupState !== EMPTY_OBJ && hasOwn(setupState, key)) || (type.props && hasOwn(normalizePropsOptions(type.props)[0]!, key)) || + hasOwn(renderContext, key) || hasOwn(publicPropertiesMap, key) || hasOwn(proxyTarget, key) || hasOwn(appContext.config.globalProperties, key) @@ -306,15 +324,15 @@ export function exposePropsOnDevProxyTarget( } } -export function exposeRenderContextOnDevProxyTarget( +export function exposeSetupStateOnDevProxyTarget( instance: ComponentInternalInstance ) { - const { proxyTarget, renderContext } = instance - Object.keys(toRaw(renderContext)).forEach(key => { + const { proxyTarget, setupState } = instance + Object.keys(toRaw(setupState)).forEach(key => { Object.defineProperty(proxyTarget, key, { enumerable: true, configurable: true, - get: () => renderContext[key], + get: () => setupState[key], set: NOOP }) }) diff --git a/packages/runtime-core/src/renderer.ts b/packages/runtime-core/src/renderer.ts index 39fbb3f1..ad755100 100644 --- a/packages/runtime-core/src/renderer.ts +++ b/packages/runtime-core/src/renderer.ts @@ -1899,14 +1899,14 @@ function baseCreateRenderer( } const oldRef = oldRawRef && oldRawRef[1] const refs = owner.refs === EMPTY_OBJ ? (owner.refs = {}) : owner.refs - const renderContext = owner.renderContext + const setupState = owner.setupState // unset old ref if (oldRef != null && oldRef !== ref) { if (isString(oldRef)) { refs[oldRef] = null - if (hasOwn(renderContext, oldRef)) { - renderContext[oldRef] = null + if (hasOwn(setupState, oldRef)) { + setupState[oldRef] = null } } else if (isRef(oldRef)) { oldRef.value = null @@ -1915,8 +1915,8 @@ function baseCreateRenderer( if (isString(ref)) { refs[ref] = value - if (hasOwn(renderContext, ref)) { - renderContext[ref] = value + if (hasOwn(setupState, ref)) { + setupState[ref] = value } } else if (isRef(ref)) { ref.value = value