wip: $data should only expose properties from data()
This commit is contained in:
parent
94a05561f8
commit
7eed0df3c2
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user