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
// 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),
}
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) {
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__) {
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)
}
}
}
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
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 }
[LifecycleHooks.ACTIVATED]: LifecycleHook
[LifecycleHooks.DEACTIVATED]: LifecycleHook
[LifecycleHooks.ERROR_CAPTURED]: LifecycleHook
-} & SetupContext
+}
// createComponent
// overload 1: direct setup function
provides: parent ? parent.provides : Object.create(appContext.provides),
// setup context properties
+ renderContext: EMPTY_OBJ,
data: EMPTY_OBJ,
props: EMPTY_OBJ,
attrs: EMPTY_OBJ,
// 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: ${
if (__FEATURE_OPTIONS__) {
applyOptions(instance, Component)
}
- if (instance.data === EMPTY_OBJ) {
- instance.data = reactive({})
+ if (instance.renderContext === EMPTY_OBJ) {
+ instance.renderContext = reactive({})
}
currentInstance = null
}
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]
case '$el':
return target.vnode.el
case '$options':
- // TODO handle merging
return target.type
default:
// methods are only exposed when options are supported
}
},
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
return false
} else {
target.user[key] = value
- return true
}
+ return true
}
}
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
}
}
if (isString(ref)) {
- const setupRef = rawData[ref]
+ const setupRef = renderContext[ref]
if (isRef(setupRef)) {
setupRef.value = value
}