type RenderFunction<Props = {}, RawBindings = {}> = <
Bindings extends UnwrapRef<RawBindings>
>(
- this: ComponentRenderProxy<Props, Bindings>,
- ctx: ComponentRenderProxy<Props, Bindings>
+ this: ComponentRenderProxy<Props, Bindings>
) => VNodeChild
interface ComponentOptionsWithoutProps<Props = Data, RawBindings = Data> {
interface SetupContext {
attrs: Data
slots: Slots
- refs: Data
emit: ((event: string, ...args: unknown[]) => void)
}
renderProxy: ComponentRenderProxy | null
propsProxy: P | null
setupContext: SetupContext | null
+ refs: Data
// user namespace
user: { [key: string]: any }
const Component = instance.type as ComponentOptions
// 1. create render proxy
instance.renderProxy = new Proxy(instance, RenderProxyHandlers) as any
- // 2. call setup()
+ // 2. create props proxy
+ // the propsProxy is a reactive AND readonly proxy to the actual props.
+ // it will be updated in resolveProps() on updates before render
+ const propsProxy = (instance.propsProxy = readonly(instance.props))
+ // 3. call setup()
const { setup } = Component
if (setup) {
- // the props proxy makes the props object passed to setup() reactive
- // so props change can be tracked by watchers
- // it will be updated in resolveProps() on updates before render
- const propsProxy = (instance.propsProxy = setup.length
- ? readonly(instance.props)
- : null)
const setupContext = (instance.setupContext =
setup.length > 1 ? createSetupContext(instance) : null)
type: Component,
vnode,
renderProxy,
- setupContext,
props,
slots,
attrs,
- refs,
emit
} = instance
try {
if (vnode.shapeFlag & ShapeFlags.STATEFUL_COMPONENT) {
result = normalizeVNode(
- (instance.render as RenderFunction).call(
- renderProxy,
- props,
- setupContext
- )
+ (instance.render as RenderFunction).call(renderProxy)
)
} else {
// functional
? render(props, {
attrs,
slots,
- refs,
emit
})
: render(props, null as any)
export const RenderProxyHandlers = {
get(target: ComponentInstance, key: string) {
- const { data, props } = target
+ const { data, props, propsProxy } = target
if (data.hasOwnProperty(key)) {
return data[key]
} else if (props.hasOwnProperty(key)) {
- return props[key]
+ // return the value from propsProxy for ref unwrapping and readonly
+ return (propsProxy as any)[key]
} else {
switch (key) {
case '$data':
return data
case '$props':
- return props
+ return propsProxy
case '$attrs':
return target.attrs
case '$slots':