wip: separate setupState
This commit is contained in:
parent
0709380c5f
commit
b2662a62c5
@ -35,7 +35,7 @@ describe('component: proxy', () => {
|
|||||||
expect(instance!.data.foo).toBe(2)
|
expect(instance!.data.foo).toBe(2)
|
||||||
})
|
})
|
||||||
|
|
||||||
test('renderContext', () => {
|
test('setupState', () => {
|
||||||
let instance: ComponentInternalInstance
|
let instance: ComponentInternalInstance
|
||||||
let instanceProxy: any
|
let instanceProxy: any
|
||||||
const Comp = {
|
const Comp = {
|
||||||
@ -55,7 +55,7 @@ describe('component: proxy', () => {
|
|||||||
render(h(Comp), nodeOps.createElement('div'))
|
render(h(Comp), nodeOps.createElement('div'))
|
||||||
expect(instanceProxy.foo).toBe(1)
|
expect(instanceProxy.foo).toBe(1)
|
||||||
instanceProxy.foo = 2
|
instanceProxy.foo = 2
|
||||||
expect(instance!.renderContext.foo).toBe(2)
|
expect(instance!.setupState.foo).toBe(2)
|
||||||
})
|
})
|
||||||
|
|
||||||
test('should not expose non-declared props', () => {
|
test('should not expose non-declared props', () => {
|
||||||
|
@ -13,7 +13,7 @@ import {
|
|||||||
RuntimeCompiledPublicInstanceProxyHandlers,
|
RuntimeCompiledPublicInstanceProxyHandlers,
|
||||||
createDevProxyTarget,
|
createDevProxyTarget,
|
||||||
exposePropsOnDevProxyTarget,
|
exposePropsOnDevProxyTarget,
|
||||||
exposeRenderContextOnDevProxyTarget
|
exposeSetupStateOnDevProxyTarget
|
||||||
} from './componentProxy'
|
} from './componentProxy'
|
||||||
import { ComponentPropsOptions, initProps } from './componentProps'
|
import { ComponentPropsOptions, initProps } from './componentProps'
|
||||||
import { Slots, initSlots, InternalSlots } from './componentSlots'
|
import { Slots, initSlots, InternalSlots } from './componentSlots'
|
||||||
@ -143,6 +143,13 @@ export interface ComponentInternalInstance {
|
|||||||
attrs: Data
|
attrs: Data
|
||||||
slots: InternalSlots
|
slots: InternalSlots
|
||||||
proxy: ComponentPublicInstance | null
|
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
|
// 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
|
// 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
|
// 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
|
// alternative proxy used only for runtime-compiled render functions using
|
||||||
// `with` block
|
// `with` block
|
||||||
withProxy: ComponentPublicInstance | null
|
withProxy: ComponentPublicInstance | null
|
||||||
setupContext: SetupContext | null
|
|
||||||
refs: Data
|
|
||||||
emit: EmitFn
|
|
||||||
|
|
||||||
// suspense related
|
// suspense related
|
||||||
suspense: SuspenseBoundary | null
|
suspense: SuspenseBoundary | null
|
||||||
@ -209,19 +213,20 @@ export function createComponentInstance(
|
|||||||
proxy: null,
|
proxy: null,
|
||||||
proxyTarget: null!, // to be immediately set
|
proxyTarget: null!, // to be immediately set
|
||||||
withProxy: null,
|
withProxy: null,
|
||||||
setupContext: null,
|
|
||||||
effects: null,
|
effects: null,
|
||||||
provides: parent ? parent.provides : Object.create(appContext.provides),
|
provides: parent ? parent.provides : Object.create(appContext.provides),
|
||||||
accessCache: null!,
|
accessCache: null!,
|
||||||
renderCache: [],
|
renderCache: [],
|
||||||
|
|
||||||
// setup context properties
|
// state
|
||||||
renderContext: EMPTY_OBJ,
|
renderContext: EMPTY_OBJ,
|
||||||
data: EMPTY_OBJ,
|
data: EMPTY_OBJ,
|
||||||
props: EMPTY_OBJ,
|
props: EMPTY_OBJ,
|
||||||
attrs: EMPTY_OBJ,
|
attrs: EMPTY_OBJ,
|
||||||
slots: EMPTY_OBJ,
|
slots: EMPTY_OBJ,
|
||||||
refs: EMPTY_OBJ,
|
refs: EMPTY_OBJ,
|
||||||
|
setupState: EMPTY_OBJ,
|
||||||
|
setupContext: null,
|
||||||
|
|
||||||
// per-instance asset storage (mutable during options resolution)
|
// per-instance asset storage (mutable during options resolution)
|
||||||
components: Object.create(appContext.components),
|
components: Object.create(appContext.components),
|
||||||
@ -392,9 +397,9 @@ export function handleSetupResult(
|
|||||||
}
|
}
|
||||||
// setup returned bindings.
|
// setup returned bindings.
|
||||||
// assuming a render function compiled from template is present.
|
// assuming a render function compiled from template is present.
|
||||||
instance.renderContext = reactive(setupResult)
|
instance.setupState = reactive(setupResult)
|
||||||
if (__DEV__) {
|
if (__DEV__) {
|
||||||
exposeRenderContextOnDevProxyTarget(instance)
|
exposeSetupStateOnDevProxyTarget(instance)
|
||||||
}
|
}
|
||||||
} else if (__DEV__ && setupResult !== undefined) {
|
} else if (__DEV__ && setupResult !== undefined) {
|
||||||
warn(
|
warn(
|
||||||
|
@ -76,9 +76,10 @@ const publicPropertiesMap: Record<
|
|||||||
}
|
}
|
||||||
|
|
||||||
const enum AccessTypes {
|
const enum AccessTypes {
|
||||||
|
SETUP,
|
||||||
DATA,
|
DATA,
|
||||||
CONTEXT,
|
|
||||||
PROPS,
|
PROPS,
|
||||||
|
CONTEXT,
|
||||||
OTHER
|
OTHER
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -91,6 +92,7 @@ export const PublicInstanceProxyHandlers: ProxyHandler<any> = {
|
|||||||
get({ _: instance }: ComponentPublicProxyTarget, key: string) {
|
get({ _: instance }: ComponentPublicProxyTarget, key: string) {
|
||||||
const {
|
const {
|
||||||
renderContext,
|
renderContext,
|
||||||
|
setupState,
|
||||||
data,
|
data,
|
||||||
props,
|
props,
|
||||||
accessCache,
|
accessCache,
|
||||||
@ -109,6 +111,8 @@ export const PublicInstanceProxyHandlers: ProxyHandler<any> = {
|
|||||||
const n = accessCache![key]
|
const n = accessCache![key]
|
||||||
if (n !== undefined) {
|
if (n !== undefined) {
|
||||||
switch (n) {
|
switch (n) {
|
||||||
|
case AccessTypes.SETUP:
|
||||||
|
return setupState[key]
|
||||||
case AccessTypes.DATA:
|
case AccessTypes.DATA:
|
||||||
return data[key]
|
return data[key]
|
||||||
case AccessTypes.CONTEXT:
|
case AccessTypes.CONTEXT:
|
||||||
@ -117,24 +121,27 @@ export const PublicInstanceProxyHandlers: ProxyHandler<any> = {
|
|||||||
return props![key]
|
return props![key]
|
||||||
// default: just fallthrough
|
// 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)) {
|
} else if (data !== EMPTY_OBJ && hasOwn(data, key)) {
|
||||||
accessCache![key] = AccessTypes.DATA
|
accessCache![key] = AccessTypes.DATA
|
||||||
return data[key]
|
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)) {
|
} else if (renderContext !== EMPTY_OBJ && hasOwn(renderContext, key)) {
|
||||||
accessCache![key] = AccessTypes.CONTEXT
|
accessCache![key] = AccessTypes.CONTEXT
|
||||||
return renderContext[key]
|
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 {
|
} else {
|
||||||
accessCache![key] = AccessTypes.OTHER
|
accessCache![key] = AccessTypes.OTHER
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// public $xxx properties &
|
// public $xxx properties &
|
||||||
// user-attached properties (falls through to proxyTarget)
|
// user-attached properties (falls through to proxyTarget)
|
||||||
@ -170,9 +177,18 @@ export const PublicInstanceProxyHandlers: ProxyHandler<any> = {
|
|||||||
key: string,
|
key: string,
|
||||||
value: any
|
value: any
|
||||||
): boolean {
|
): boolean {
|
||||||
const { data, renderContext } = instance
|
const { data, setupState, renderContext } = instance
|
||||||
if (data !== EMPTY_OBJ && hasOwn(data, key)) {
|
if (setupState !== EMPTY_OBJ && hasOwn(setupState, key)) {
|
||||||
|
setupState[key] = value
|
||||||
|
} else if (data !== EMPTY_OBJ && hasOwn(data, key)) {
|
||||||
data[key] = value
|
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)) {
|
} else if (hasOwn(renderContext, key)) {
|
||||||
renderContext[key] = value
|
renderContext[key] = value
|
||||||
} else if (key[0] === '$' && key.slice(1) in instance) {
|
} else if (key[0] === '$' && key.slice(1) in instance) {
|
||||||
@ -183,13 +199,6 @@ export const PublicInstanceProxyHandlers: ProxyHandler<any> = {
|
|||||||
instance
|
instance
|
||||||
)
|
)
|
||||||
return false
|
return false
|
||||||
} else if (key in instance.props) {
|
|
||||||
__DEV__ &&
|
|
||||||
warn(
|
|
||||||
`Attempting to mutate prop "${key}". Props are readonly.`,
|
|
||||||
instance
|
|
||||||
)
|
|
||||||
return false
|
|
||||||
} else {
|
} else {
|
||||||
if (__DEV__ && key in instance.appContext.config.globalProperties) {
|
if (__DEV__ && key in instance.appContext.config.globalProperties) {
|
||||||
Object.defineProperty(instance.proxyTarget, key, {
|
Object.defineProperty(instance.proxyTarget, key, {
|
||||||
@ -206,15 +215,24 @@ export const PublicInstanceProxyHandlers: ProxyHandler<any> = {
|
|||||||
|
|
||||||
has(
|
has(
|
||||||
{
|
{
|
||||||
_: { data, accessCache, renderContext, type, proxyTarget, appContext }
|
_: {
|
||||||
|
data,
|
||||||
|
setupState,
|
||||||
|
accessCache,
|
||||||
|
renderContext,
|
||||||
|
type,
|
||||||
|
proxyTarget,
|
||||||
|
appContext
|
||||||
|
}
|
||||||
}: ComponentPublicProxyTarget,
|
}: ComponentPublicProxyTarget,
|
||||||
key: string
|
key: string
|
||||||
) {
|
) {
|
||||||
return (
|
return (
|
||||||
accessCache![key] !== undefined ||
|
accessCache![key] !== undefined ||
|
||||||
(data !== EMPTY_OBJ && hasOwn(data, key)) ||
|
(data !== EMPTY_OBJ && hasOwn(data, key)) ||
|
||||||
hasOwn(renderContext, key) ||
|
(setupState !== EMPTY_OBJ && hasOwn(setupState, key)) ||
|
||||||
(type.props && hasOwn(normalizePropsOptions(type.props)[0]!, key)) ||
|
(type.props && hasOwn(normalizePropsOptions(type.props)[0]!, key)) ||
|
||||||
|
hasOwn(renderContext, key) ||
|
||||||
hasOwn(publicPropertiesMap, key) ||
|
hasOwn(publicPropertiesMap, key) ||
|
||||||
hasOwn(proxyTarget, key) ||
|
hasOwn(proxyTarget, key) ||
|
||||||
hasOwn(appContext.config.globalProperties, key)
|
hasOwn(appContext.config.globalProperties, key)
|
||||||
@ -306,15 +324,15 @@ export function exposePropsOnDevProxyTarget(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function exposeRenderContextOnDevProxyTarget(
|
export function exposeSetupStateOnDevProxyTarget(
|
||||||
instance: ComponentInternalInstance
|
instance: ComponentInternalInstance
|
||||||
) {
|
) {
|
||||||
const { proxyTarget, renderContext } = instance
|
const { proxyTarget, setupState } = instance
|
||||||
Object.keys(toRaw(renderContext)).forEach(key => {
|
Object.keys(toRaw(setupState)).forEach(key => {
|
||||||
Object.defineProperty(proxyTarget, key, {
|
Object.defineProperty(proxyTarget, key, {
|
||||||
enumerable: true,
|
enumerable: true,
|
||||||
configurable: true,
|
configurable: true,
|
||||||
get: () => renderContext[key],
|
get: () => setupState[key],
|
||||||
set: NOOP
|
set: NOOP
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
@ -1899,14 +1899,14 @@ function baseCreateRenderer(
|
|||||||
}
|
}
|
||||||
const oldRef = oldRawRef && oldRawRef[1]
|
const oldRef = oldRawRef && oldRawRef[1]
|
||||||
const refs = owner.refs === EMPTY_OBJ ? (owner.refs = {}) : owner.refs
|
const refs = owner.refs === EMPTY_OBJ ? (owner.refs = {}) : owner.refs
|
||||||
const renderContext = owner.renderContext
|
const setupState = owner.setupState
|
||||||
|
|
||||||
// unset old ref
|
// unset old ref
|
||||||
if (oldRef != null && oldRef !== ref) {
|
if (oldRef != null && oldRef !== ref) {
|
||||||
if (isString(oldRef)) {
|
if (isString(oldRef)) {
|
||||||
refs[oldRef] = null
|
refs[oldRef] = null
|
||||||
if (hasOwn(renderContext, oldRef)) {
|
if (hasOwn(setupState, oldRef)) {
|
||||||
renderContext[oldRef] = null
|
setupState[oldRef] = null
|
||||||
}
|
}
|
||||||
} else if (isRef(oldRef)) {
|
} else if (isRef(oldRef)) {
|
||||||
oldRef.value = null
|
oldRef.value = null
|
||||||
@ -1915,8 +1915,8 @@ function baseCreateRenderer(
|
|||||||
|
|
||||||
if (isString(ref)) {
|
if (isString(ref)) {
|
||||||
refs[ref] = value
|
refs[ref] = value
|
||||||
if (hasOwn(renderContext, ref)) {
|
if (hasOwn(setupState, ref)) {
|
||||||
renderContext[ref] = value
|
setupState[ref] = value
|
||||||
}
|
}
|
||||||
} else if (isRef(ref)) {
|
} else if (isRef(ref)) {
|
||||||
ref.value = value
|
ref.value = value
|
||||||
|
Loading…
Reference in New Issue
Block a user