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,
|
options: ComponentOptions,
|
||||||
asMixin: boolean = false
|
asMixin: boolean = false
|
||||||
) {
|
) {
|
||||||
const data =
|
const renderContext =
|
||||||
instance.data === EMPTY_OBJ ? (instance.data = reactive({})) : instance.data
|
instance.renderContext === EMPTY_OBJ
|
||||||
|
? (instance.renderContext = reactive({}))
|
||||||
|
: instance.renderContext
|
||||||
const ctx = instance.renderProxy as any
|
const ctx = instance.renderProxy as any
|
||||||
const {
|
const {
|
||||||
// composition
|
// composition
|
||||||
@ -166,12 +168,16 @@ export function applyOptions(
|
|||||||
|
|
||||||
// state options
|
// state options
|
||||||
if (dataOptions) {
|
if (dataOptions) {
|
||||||
|
const data =
|
||||||
|
instance.data === EMPTY_OBJ
|
||||||
|
? (instance.data = reactive({}))
|
||||||
|
: instance.data
|
||||||
extend(data, isFunction(dataOptions) ? dataOptions.call(ctx) : dataOptions)
|
extend(data, isFunction(dataOptions) ? dataOptions.call(ctx) : dataOptions)
|
||||||
}
|
}
|
||||||
if (computedOptions) {
|
if (computedOptions) {
|
||||||
for (const key in computedOptions) {
|
for (const key in computedOptions) {
|
||||||
const opt = (computedOptions as ComputedOptions)[key]
|
const opt = (computedOptions as ComputedOptions)[key]
|
||||||
data[key] = isFunction(opt)
|
renderContext[key] = isFunction(opt)
|
||||||
? computed(opt.bind(ctx))
|
? computed(opt.bind(ctx))
|
||||||
: computed({
|
: computed({
|
||||||
get: opt.get.bind(ctx),
|
get: opt.get.bind(ctx),
|
||||||
@ -181,7 +187,7 @@ export function applyOptions(
|
|||||||
}
|
}
|
||||||
if (methods) {
|
if (methods) {
|
||||||
for (const key in methods) {
|
for (const key in methods) {
|
||||||
data[key] = (methods as MethodOptions)[key].bind(ctx)
|
renderContext[key] = (methods as MethodOptions)[key].bind(ctx)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (watchOptions) {
|
if (watchOptions) {
|
||||||
@ -189,7 +195,7 @@ export function applyOptions(
|
|||||||
const raw = watchOptions[key]
|
const raw = watchOptions[key]
|
||||||
const getter = () => ctx[key]
|
const getter = () => ctx[key]
|
||||||
if (isString(raw)) {
|
if (isString(raw)) {
|
||||||
const handler = data[raw]
|
const handler = renderContext[raw]
|
||||||
if (isFunction(handler)) {
|
if (isFunction(handler)) {
|
||||||
watch(getter, handler as any)
|
watch(getter, handler as any)
|
||||||
} else if (__DEV__) {
|
} else if (__DEV__) {
|
||||||
@ -217,15 +223,15 @@ export function applyOptions(
|
|||||||
if (isArray(injectOptions)) {
|
if (isArray(injectOptions)) {
|
||||||
for (let i = 0; i < injectOptions.length; i++) {
|
for (let i = 0; i < injectOptions.length; i++) {
|
||||||
const key = injectOptions[i]
|
const key = injectOptions[i]
|
||||||
data[key] = inject(key)
|
renderContext[key] = inject(key)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for (const key in injectOptions) {
|
for (const key in injectOptions) {
|
||||||
const opt = injectOptions[key]
|
const opt = injectOptions[key]
|
||||||
if (isObject(opt)) {
|
if (isObject(opt)) {
|
||||||
data[key] = inject(opt.from, opt.default)
|
renderContext[key] = inject(opt.from, opt.default)
|
||||||
} else {
|
} else {
|
||||||
data[key] = inject(opt)
|
renderContext[key] = inject(opt)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -144,15 +144,17 @@ export const enum LifecycleHooks {
|
|||||||
ERROR_CAPTURED = 'ec'
|
ERROR_CAPTURED = 'ec'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Emit = ((event: string, ...args: unknown[]) => void)
|
||||||
|
|
||||||
interface SetupContext {
|
interface SetupContext {
|
||||||
attrs: Data
|
attrs: Data
|
||||||
slots: Slots
|
slots: Slots
|
||||||
emit: ((event: string, ...args: unknown[]) => void)
|
emit: Emit
|
||||||
}
|
}
|
||||||
|
|
||||||
type RenderFunction = () => VNodeChild
|
type RenderFunction = () => VNodeChild
|
||||||
|
|
||||||
export type ComponentInstance<P = Data, D = Data> = {
|
export interface ComponentInstance {
|
||||||
type: FunctionalComponent | ComponentOptions
|
type: FunctionalComponent | ComponentOptions
|
||||||
parent: ComponentInstance | null
|
parent: ComponentInstance | null
|
||||||
appContext: AppContext
|
appContext: AppContext
|
||||||
@ -169,12 +171,16 @@ export type ComponentInstance<P = Data, D = Data> = {
|
|||||||
directives: Record<string, Directive>
|
directives: Record<string, Directive>
|
||||||
|
|
||||||
// the rest are only for stateful components
|
// the rest are only for stateful components
|
||||||
data: D
|
renderContext: Data
|
||||||
props: P
|
data: Data
|
||||||
|
props: Data
|
||||||
|
attrs: Data
|
||||||
|
slots: Slots
|
||||||
renderProxy: ComponentRenderProxy | null
|
renderProxy: ComponentRenderProxy | null
|
||||||
propsProxy: P | null
|
propsProxy: Data | null
|
||||||
setupContext: SetupContext | null
|
setupContext: SetupContext | null
|
||||||
refs: Data
|
refs: Data
|
||||||
|
emit: Emit
|
||||||
|
|
||||||
// user namespace
|
// user namespace
|
||||||
user: { [key: string]: any }
|
user: { [key: string]: any }
|
||||||
@ -193,7 +199,7 @@ export type ComponentInstance<P = Data, D = Data> = {
|
|||||||
[LifecycleHooks.ACTIVATED]: LifecycleHook
|
[LifecycleHooks.ACTIVATED]: LifecycleHook
|
||||||
[LifecycleHooks.DEACTIVATED]: LifecycleHook
|
[LifecycleHooks.DEACTIVATED]: LifecycleHook
|
||||||
[LifecycleHooks.ERROR_CAPTURED]: LifecycleHook
|
[LifecycleHooks.ERROR_CAPTURED]: LifecycleHook
|
||||||
} & SetupContext
|
}
|
||||||
|
|
||||||
// createComponent
|
// createComponent
|
||||||
// overload 1: direct setup function
|
// overload 1: direct setup function
|
||||||
@ -287,6 +293,7 @@ export function createComponentInstance(
|
|||||||
provides: parent ? parent.provides : Object.create(appContext.provides),
|
provides: parent ? parent.provides : Object.create(appContext.provides),
|
||||||
|
|
||||||
// setup context properties
|
// setup context properties
|
||||||
|
renderContext: EMPTY_OBJ,
|
||||||
data: EMPTY_OBJ,
|
data: EMPTY_OBJ,
|
||||||
props: EMPTY_OBJ,
|
props: EMPTY_OBJ,
|
||||||
attrs: EMPTY_OBJ,
|
attrs: EMPTY_OBJ,
|
||||||
@ -397,7 +404,7 @@ export function setupStatefulComponent(instance: ComponentInstance) {
|
|||||||
// setup returned bindings.
|
// setup returned bindings.
|
||||||
// assuming a render function compiled from template is present.
|
// assuming a render function compiled from template is present.
|
||||||
if (isObject(setupResult)) {
|
if (isObject(setupResult)) {
|
||||||
instance.data = reactive(setupResult)
|
instance.renderContext = reactive(setupResult)
|
||||||
} else if (__DEV__ && setupResult !== undefined) {
|
} else if (__DEV__ && setupResult !== undefined) {
|
||||||
warn(
|
warn(
|
||||||
`setup() should return an object. Received: ${
|
`setup() should return an object. Received: ${
|
||||||
@ -420,8 +427,8 @@ export function setupStatefulComponent(instance: ComponentInstance) {
|
|||||||
if (__FEATURE_OPTIONS__) {
|
if (__FEATURE_OPTIONS__) {
|
||||||
applyOptions(instance, Component)
|
applyOptions(instance, Component)
|
||||||
}
|
}
|
||||||
if (instance.data === EMPTY_OBJ) {
|
if (instance.renderContext === EMPTY_OBJ) {
|
||||||
instance.data = reactive({})
|
instance.renderContext = reactive({})
|
||||||
}
|
}
|
||||||
currentInstance = null
|
currentInstance = null
|
||||||
}
|
}
|
||||||
|
@ -1,12 +1,15 @@
|
|||||||
import { ComponentInstance } from './component'
|
import { ComponentInstance } from './component'
|
||||||
import { nextTick } from './scheduler'
|
import { nextTick } from './scheduler'
|
||||||
import { instanceWatch } from './apiWatch'
|
import { instanceWatch } from './apiWatch'
|
||||||
|
import { EMPTY_OBJ } from '@vue/shared'
|
||||||
|
|
||||||
export const RenderProxyHandlers = {
|
export const RenderProxyHandlers = {
|
||||||
get(target: ComponentInstance, key: string) {
|
get(target: ComponentInstance, key: string) {
|
||||||
const { data, props, propsProxy } = target
|
const { renderContext, data, props, propsProxy } = target
|
||||||
if (data.hasOwnProperty(key)) {
|
if (data !== EMPTY_OBJ && data.hasOwnProperty(key)) {
|
||||||
return data[key]
|
return data[key]
|
||||||
|
} else if (renderContext.hasOwnProperty(key)) {
|
||||||
|
return renderContext[key]
|
||||||
} else if (props.hasOwnProperty(key)) {
|
} else if (props.hasOwnProperty(key)) {
|
||||||
// return the value from propsProxy for ref unwrapping and readonly
|
// return the value from propsProxy for ref unwrapping and readonly
|
||||||
return (propsProxy as any)[key]
|
return (propsProxy as any)[key]
|
||||||
@ -31,7 +34,6 @@ export const RenderProxyHandlers = {
|
|||||||
case '$el':
|
case '$el':
|
||||||
return target.vnode.el
|
return target.vnode.el
|
||||||
case '$options':
|
case '$options':
|
||||||
// TODO handle merging
|
|
||||||
return target.type
|
return target.type
|
||||||
default:
|
default:
|
||||||
// methods are only exposed when options are supported
|
// methods are only exposed when options are supported
|
||||||
@ -50,10 +52,11 @@ export const RenderProxyHandlers = {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
set(target: ComponentInstance, key: string, value: any): boolean {
|
set(target: ComponentInstance, key: string, value: any): boolean {
|
||||||
const { data } = target
|
const { data, renderContext } = target
|
||||||
if (data.hasOwnProperty(key)) {
|
if (data !== EMPTY_OBJ && data.hasOwnProperty(key)) {
|
||||||
data[key] = value
|
data[key] = value
|
||||||
return true
|
} else if (renderContext.hasOwnProperty(key)) {
|
||||||
|
renderContext[key] = value
|
||||||
} else if (key[0] === '$' && key.slice(1) in target) {
|
} else if (key[0] === '$' && key.slice(1) in target) {
|
||||||
// TODO warn attempt of mutating public property
|
// TODO warn attempt of mutating public property
|
||||||
return false
|
return false
|
||||||
@ -62,7 +65,7 @@ export const RenderProxyHandlers = {
|
|||||||
return false
|
return false
|
||||||
} else {
|
} else {
|
||||||
target.user[key] = value
|
target.user[key] = value
|
||||||
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1127,13 +1127,13 @@ export function createRenderer(options: RendererOptions): RootRenderFunction {
|
|||||||
value: HostNode | ComponentInstance | null
|
value: HostNode | ComponentInstance | null
|
||||||
) {
|
) {
|
||||||
const refs = parent.refs === EMPTY_OBJ ? (parent.refs = {}) : parent.refs
|
const refs = parent.refs === EMPTY_OBJ ? (parent.refs = {}) : parent.refs
|
||||||
const rawData = toRaw(parent.data)
|
const renderContext = toRaw(parent.renderContext)
|
||||||
|
|
||||||
// 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
|
||||||
const oldSetupRef = rawData[oldRef]
|
const oldSetupRef = renderContext[oldRef]
|
||||||
if (isRef(oldSetupRef)) {
|
if (isRef(oldSetupRef)) {
|
||||||
oldSetupRef.value = null
|
oldSetupRef.value = null
|
||||||
}
|
}
|
||||||
@ -1143,7 +1143,7 @@ export function createRenderer(options: RendererOptions): RootRenderFunction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (isString(ref)) {
|
if (isString(ref)) {
|
||||||
const setupRef = rawData[ref]
|
const setupRef = renderContext[ref]
|
||||||
if (isRef(setupRef)) {
|
if (isRef(setupRef)) {
|
||||||
setupRef.value = value
|
setupRef.value = value
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user