wip: render() should receive no args, expose props on renderContext as readonly

This commit is contained in:
Evan You 2019-09-03 15:27:59 -04:00
parent 9f63a54203
commit c5ec29ff9b
3 changed files with 21 additions and 29 deletions

View File

@ -41,7 +41,8 @@ test('createComponent type inference', () => {
}
}
},
render(props) {
render() {
const props = this.$props
props.a && props.a * 2
props.b.slice()
props.bb.slice()
@ -68,9 +69,9 @@ test('type inference w/ optional props declaration', () => {
a: 1
}
},
render(ctx) {
ctx.msg
ctx.a * 2
render() {
this.$props.msg
this.$data.a * 2
this.msg
this.a * 2
}
@ -95,10 +96,10 @@ test('type inference w/ array props declaration', () => {
c: 1
}
},
render(ctx) {
ctx.a
ctx.b
ctx.c
render() {
this.$props.a
this.$props.b
this.$data.c
this.a
this.b
this.c

View File

@ -39,8 +39,7 @@ type SetupFunction<Props, RawBindings> = (
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> {
@ -103,7 +102,6 @@ export const enum LifecycleHooks {
interface SetupContext {
attrs: Data
slots: Slots
refs: Data
emit: ((event: string, ...args: unknown[]) => void)
}
@ -126,6 +124,7 @@ export type ComponentInstance<P = Data, S = Data> = {
renderProxy: ComponentRenderProxy | null
propsProxy: P | null
setupContext: SetupContext | null
refs: Data
// user namespace
user: { [key: string]: any }
@ -280,15 +279,13 @@ export function setupStatefulComponent(instance: ComponentInstance) {
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)
@ -373,11 +370,9 @@ export function renderComponentRoot(instance: ComponentInstance): VNode {
type: Component,
vnode,
renderProxy,
setupContext,
props,
slots,
attrs,
refs,
emit
} = instance
@ -386,11 +381,7 @@ export function renderComponentRoot(instance: ComponentInstance): VNode {
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
@ -400,7 +391,6 @@ export function renderComponentRoot(instance: ComponentInstance): VNode {
? render(props, {
attrs,
slots,
refs,
emit
})
: render(props, null as any)

View File

@ -2,17 +2,18 @@ import { ComponentInstance } from './component'
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':