refactor: adjust props initialization/updating
This commit is contained in:
parent
e05673f4d3
commit
b08b15dba0
@ -19,8 +19,6 @@ import {
|
|||||||
} from '@vue/shared'
|
} from '@vue/shared'
|
||||||
import { warn } from './warning'
|
import { warn } from './warning'
|
||||||
|
|
||||||
const EMPTY_PROPS = { props: EMPTY_OBJ }
|
|
||||||
|
|
||||||
const enum BooleanFlags {
|
const enum BooleanFlags {
|
||||||
shouldCast = '1',
|
shouldCast = '1',
|
||||||
shouldCastTrue = '2'
|
shouldCastTrue = '2'
|
||||||
@ -38,9 +36,11 @@ export function initializeProps(
|
|||||||
options: NormalizedPropsOptions | undefined,
|
options: NormalizedPropsOptions | undefined,
|
||||||
data: Data | null
|
data: Data | null
|
||||||
) {
|
) {
|
||||||
const { props, attrs } = resolveProps(data, options)
|
const [props, attrs] = resolveProps(data, options)
|
||||||
instance.$props = immutable(props || {})
|
instance.$props = immutable(props === EMPTY_OBJ ? {} : props)
|
||||||
instance.$attrs = immutable(attrs || {})
|
instance.$attrs = options
|
||||||
|
? immutable(attrs === EMPTY_OBJ ? {} : attrs)
|
||||||
|
: instance.$props
|
||||||
}
|
}
|
||||||
|
|
||||||
// resolve raw VNode data.
|
// resolve raw VNode data.
|
||||||
@ -50,10 +50,13 @@ export function initializeProps(
|
|||||||
// - for the rest:
|
// - for the rest:
|
||||||
// - if has declared props: put declared ones in `props`, the rest in `attrs`
|
// - if has declared props: put declared ones in `props`, the rest in `attrs`
|
||||||
// - else: everything goes in `props`.
|
// - else: everything goes in `props`.
|
||||||
|
|
||||||
|
const EMPTY_PROPS = [EMPTY_OBJ, EMPTY_OBJ] as [Data, Data]
|
||||||
|
|
||||||
export function resolveProps(
|
export function resolveProps(
|
||||||
rawData: any,
|
rawData: any,
|
||||||
_options: NormalizedPropsOptions | void
|
_options: NormalizedPropsOptions | void
|
||||||
): { props: Data; attrs?: Data } {
|
): [Data, Data] {
|
||||||
const hasDeclaredProps = _options !== void 0
|
const hasDeclaredProps = _options !== void 0
|
||||||
const options = _options as NormalizedPropsOptions
|
const options = _options as NormalizedPropsOptions
|
||||||
if (!rawData && !hasDeclaredProps) {
|
if (!rawData && !hasDeclaredProps) {
|
||||||
@ -109,44 +112,48 @@ export function resolveProps(
|
|||||||
// if component has no declared props, $attrs === $props
|
// if component has no declared props, $attrs === $props
|
||||||
attrs = props
|
attrs = props
|
||||||
}
|
}
|
||||||
return { props, attrs }
|
return [props, attrs]
|
||||||
}
|
}
|
||||||
|
|
||||||
export function updateProps(instance: ComponentInstance, nextData: Data) {
|
export function updateProps(
|
||||||
|
instance: ComponentInstance,
|
||||||
|
nextData: Data | null
|
||||||
|
) {
|
||||||
// instance.$props and instance.$attrs are observables that should not be
|
// instance.$props and instance.$attrs are observables that should not be
|
||||||
// replaced. Instead, we mutate them to match latest props, which will trigger
|
// replaced. Instead, we mutate them to match latest props, which will trigger
|
||||||
// updates if any value that's been used in child component has changed.
|
// updates if any value that's been used in child component has changed.
|
||||||
if (nextData != null) {
|
const [nextProps, nextAttrs] = resolveProps(nextData, instance.$options.props)
|
||||||
const { props: nextProps, attrs: nextAttrs } = resolveProps(
|
// unlock to temporarily allow mutatiing props
|
||||||
nextData,
|
unlock()
|
||||||
instance.$options.props
|
const props = instance.$props
|
||||||
)
|
const rawProps = unwrap(props)
|
||||||
// unlock to temporarily allow mutatiing props
|
const hasEmptyProps = nextProps === EMPTY_OBJ
|
||||||
unlock()
|
for (const key in rawProps) {
|
||||||
const props = instance.$props
|
if (hasEmptyProps || !nextProps.hasOwnProperty(key)) {
|
||||||
const rawProps = unwrap(props)
|
delete (props as any)[key]
|
||||||
for (const key in rawProps) {
|
|
||||||
if (!nextProps.hasOwnProperty(key)) {
|
|
||||||
delete (props as any)[key]
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
if (!hasEmptyProps) {
|
||||||
for (const key in nextProps) {
|
for (const key in nextProps) {
|
||||||
;(props as any)[key] = nextProps[key]
|
;(props as any)[key] = nextProps[key]
|
||||||
}
|
}
|
||||||
if (nextAttrs) {
|
}
|
||||||
const attrs = instance.$attrs
|
const attrs = instance.$attrs
|
||||||
const rawAttrs = unwrap(attrs)
|
if (attrs !== props) {
|
||||||
for (const key in rawAttrs) {
|
const rawAttrs = unwrap(attrs)
|
||||||
if (!nextAttrs.hasOwnProperty(key)) {
|
const hasEmptyAttrs = nextAttrs === EMPTY_OBJ
|
||||||
delete attrs[key]
|
for (const key in rawAttrs) {
|
||||||
}
|
if (hasEmptyAttrs || !nextAttrs.hasOwnProperty(key)) {
|
||||||
|
delete attrs[key]
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
if (!hasEmptyAttrs) {
|
||||||
for (const key in nextAttrs) {
|
for (const key in nextAttrs) {
|
||||||
attrs[key] = nextAttrs[key]
|
attrs[key] = nextAttrs[key]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
lock()
|
|
||||||
}
|
}
|
||||||
|
lock()
|
||||||
}
|
}
|
||||||
|
|
||||||
export function normalizePropsOptions(
|
export function normalizePropsOptions(
|
||||||
|
@ -119,10 +119,10 @@ export function renderInstanceRoot(instance: ComponentInstance): VNode {
|
|||||||
|
|
||||||
export function renderFunctionalRoot(vnode: VNode): VNode {
|
export function renderFunctionalRoot(vnode: VNode): VNode {
|
||||||
const render = vnode.tag as FunctionalComponent
|
const render = vnode.tag as FunctionalComponent
|
||||||
const { props, attrs } = resolveProps(vnode.data, render.props)
|
const [props, attrs] = resolveProps(vnode.data, render.props)
|
||||||
let subTree
|
let subTree
|
||||||
try {
|
try {
|
||||||
subTree = render(props, vnode.slots || EMPTY_OBJ, attrs || EMPTY_OBJ, vnode)
|
subTree = render(props, vnode.slots || EMPTY_OBJ, attrs, vnode)
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
handleError(err, vnode, ErrorTypes.RENDER)
|
handleError(err, vnode, ErrorTypes.RENDER)
|
||||||
}
|
}
|
||||||
|
@ -480,9 +480,7 @@ export function createRenderer(options: RendererOptions) {
|
|||||||
instance.$parentVNode = nextVNode as MountedVNode
|
instance.$parentVNode = nextVNode as MountedVNode
|
||||||
|
|
||||||
// Update props. This will trigger child update if necessary.
|
// Update props. This will trigger child update if necessary.
|
||||||
if (nextData !== null) {
|
updateProps(instance, nextData)
|
||||||
updateProps(instance, nextData)
|
|
||||||
}
|
|
||||||
|
|
||||||
// If has different slots content, or has non-compiled slots,
|
// If has different slots content, or has non-compiled slots,
|
||||||
// the child needs to be force updated. It's ok to call $forceUpdate
|
// the child needs to be force updated. It's ok to call $forceUpdate
|
||||||
|
Loading…
x
Reference in New Issue
Block a user