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

View File

@ -39,8 +39,7 @@ type SetupFunction<Props, RawBindings> = (
type RenderFunction<Props = {}, RawBindings = {}> = < type RenderFunction<Props = {}, RawBindings = {}> = <
Bindings extends UnwrapRef<RawBindings> Bindings extends UnwrapRef<RawBindings>
>( >(
this: ComponentRenderProxy<Props, Bindings>, this: ComponentRenderProxy<Props, Bindings>
ctx: ComponentRenderProxy<Props, Bindings>
) => VNodeChild ) => VNodeChild
interface ComponentOptionsWithoutProps<Props = Data, RawBindings = Data> { interface ComponentOptionsWithoutProps<Props = Data, RawBindings = Data> {
@ -103,7 +102,6 @@ export const enum LifecycleHooks {
interface SetupContext { interface SetupContext {
attrs: Data attrs: Data
slots: Slots slots: Slots
refs: Data
emit: ((event: string, ...args: unknown[]) => void) emit: ((event: string, ...args: unknown[]) => void)
} }
@ -126,6 +124,7 @@ export type ComponentInstance<P = Data, S = Data> = {
renderProxy: ComponentRenderProxy | null renderProxy: ComponentRenderProxy | null
propsProxy: P | null propsProxy: P | null
setupContext: SetupContext | null setupContext: SetupContext | null
refs: Data
// user namespace // user namespace
user: { [key: string]: any } user: { [key: string]: any }
@ -280,15 +279,13 @@ export function setupStatefulComponent(instance: ComponentInstance) {
const Component = instance.type as ComponentOptions const Component = instance.type as ComponentOptions
// 1. create render proxy // 1. create render proxy
instance.renderProxy = new Proxy(instance, RenderProxyHandlers) as any 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 const { setup } = Component
if (setup) { 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 = const setupContext = (instance.setupContext =
setup.length > 1 ? createSetupContext(instance) : null) setup.length > 1 ? createSetupContext(instance) : null)
@ -373,11 +370,9 @@ export function renderComponentRoot(instance: ComponentInstance): VNode {
type: Component, type: Component,
vnode, vnode,
renderProxy, renderProxy,
setupContext,
props, props,
slots, slots,
attrs, attrs,
refs,
emit emit
} = instance } = instance
@ -386,11 +381,7 @@ export function renderComponentRoot(instance: ComponentInstance): VNode {
try { try {
if (vnode.shapeFlag & ShapeFlags.STATEFUL_COMPONENT) { if (vnode.shapeFlag & ShapeFlags.STATEFUL_COMPONENT) {
result = normalizeVNode( result = normalizeVNode(
(instance.render as RenderFunction).call( (instance.render as RenderFunction).call(renderProxy)
renderProxy,
props,
setupContext
)
) )
} else { } else {
// functional // functional
@ -400,7 +391,6 @@ export function renderComponentRoot(instance: ComponentInstance): VNode {
? render(props, { ? render(props, {
attrs, attrs,
slots, slots,
refs,
emit emit
}) })
: render(props, null as any) : render(props, null as any)

View File

@ -2,17 +2,18 @@ import { ComponentInstance } from './component'
export const RenderProxyHandlers = { export const RenderProxyHandlers = {
get(target: ComponentInstance, key: string) { get(target: ComponentInstance, key: string) {
const { data, props } = target const { data, props, propsProxy } = target
if (data.hasOwnProperty(key)) { if (data.hasOwnProperty(key)) {
return data[key] return data[key]
} else if (props.hasOwnProperty(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 { } else {
switch (key) { switch (key) {
case '$data': case '$data':
return data return data
case '$props': case '$props':
return props return propsProxy
case '$attrs': case '$attrs':
return target.attrs return target.attrs
case '$slots': case '$slots':