feat: detailed info in renderTriggered + hint for skipping slot updates
This commit is contained in:
parent
6027d480f3
commit
64029b4a54
@ -204,9 +204,7 @@ export function shouldUpdateComponent(
|
|||||||
const { data: prevProps, childFlags: prevChildFlags } = prevVNode
|
const { data: prevProps, childFlags: prevChildFlags } = prevVNode
|
||||||
const { data: nextProps, childFlags: nextChildFlags } = nextVNode
|
const { data: nextProps, childFlags: nextChildFlags } = nextVNode
|
||||||
// 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.
|
||||||
// again even if props update has already queued an update, as the
|
|
||||||
// scheduler will not queue the same update twice.
|
|
||||||
if (
|
if (
|
||||||
prevChildFlags !== nextChildFlags ||
|
prevChildFlags !== nextChildFlags ||
|
||||||
(nextChildFlags & ChildrenFlags.DYNAMIC_SLOTS) > 0
|
(nextChildFlags & ChildrenFlags.DYNAMIC_SLOTS) > 0
|
||||||
@ -235,11 +233,49 @@ export function shouldUpdateComponent(
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DEV only
|
||||||
export function getReasonForComponentUpdate(
|
export function getReasonForComponentUpdate(
|
||||||
prevVNode: VNode,
|
prevVNode: VNode,
|
||||||
nextVNode: VNode
|
nextVNode: VNode
|
||||||
): any {
|
): any {
|
||||||
// TODO: extract more detailed information on why the component is updating
|
const reasons = []
|
||||||
|
const { childFlags: prevChildFlags } = prevVNode
|
||||||
|
const { childFlags: nextChildFlags } = nextVNode
|
||||||
|
if (
|
||||||
|
prevChildFlags !== nextChildFlags ||
|
||||||
|
(nextChildFlags & ChildrenFlags.DYNAMIC_SLOTS) > 0
|
||||||
|
) {
|
||||||
|
reasons.push({
|
||||||
|
type: `slots may have changed`,
|
||||||
|
tip: `use function slots + $stable: true to avoid slot-triggered child updates.`
|
||||||
|
})
|
||||||
|
}
|
||||||
|
const prevProps = prevVNode.data || EMPTY_OBJ
|
||||||
|
const nextProps = nextVNode.data || EMPTY_OBJ
|
||||||
|
for (const key in nextProps) {
|
||||||
|
if (nextProps[key] !== prevProps[key]) {
|
||||||
|
reasons.push({
|
||||||
|
type: 'prop changed',
|
||||||
|
key,
|
||||||
|
value: nextProps[key],
|
||||||
|
oldValue: prevProps[key]
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (const key in prevProps) {
|
||||||
|
if (!(key in nextProps)) {
|
||||||
|
reasons.push({
|
||||||
|
type: 'prop changed',
|
||||||
|
key,
|
||||||
|
value: undefined,
|
||||||
|
oldValue: prevProps[key]
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
type: 'triggered by parent',
|
||||||
|
reasons
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function createComponentClassFromOptions(
|
export function createComponentClassFromOptions(
|
||||||
|
@ -22,7 +22,8 @@ export const Portal = Symbol()
|
|||||||
type RawChildType = VNode | string | number | boolean | null | undefined
|
type RawChildType = VNode | string | number | boolean | null | undefined
|
||||||
|
|
||||||
export type RawSlots = {
|
export type RawSlots = {
|
||||||
[name: string]: () => RawChildrenType
|
$stable?: boolean
|
||||||
|
[name: string]: RawChildType | (() => RawChildrenType)
|
||||||
}
|
}
|
||||||
|
|
||||||
export type RawChildrenType = RawChildType | RawChildType[]
|
export type RawChildrenType = RawChildType | RawChildType[]
|
||||||
|
@ -10,6 +10,7 @@ import { RawChildrenType, RawSlots } from './h'
|
|||||||
import { FunctionalHandle } from './createRenderer'
|
import { FunctionalHandle } from './createRenderer'
|
||||||
|
|
||||||
const handlersRE = /^on|^vnode/
|
const handlersRE = /^on|^vnode/
|
||||||
|
const STABLE_SLOTS_HINT = '$stable'
|
||||||
|
|
||||||
// Vue core is platform agnostic, so we are not using Element for "DOM" nodes.
|
// Vue core is platform agnostic, so we are not using Element for "DOM" nodes.
|
||||||
export interface RenderNode {
|
export interface RenderNode {
|
||||||
@ -226,6 +227,10 @@ export function createComponentVNode(
|
|||||||
} else if (isObject(children) && !(children as any)._isVNode) {
|
} else if (isObject(children) && !(children as any)._isVNode) {
|
||||||
// slot object as children
|
// slot object as children
|
||||||
slots = children
|
slots = children
|
||||||
|
// special manual optimization hint for raw render fn users
|
||||||
|
if (slots[STABLE_SLOTS_HINT]) {
|
||||||
|
childFlags = ChildrenFlags.STABLE_SLOTS
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
slots = { default: () => children }
|
slots = { default: () => children }
|
||||||
}
|
}
|
||||||
@ -418,6 +423,9 @@ function normalizeSlots(slots: { [name: string]: any }): Slots {
|
|||||||
}
|
}
|
||||||
const normalized = { _normalized: true } as any
|
const normalized = { _normalized: true } as any
|
||||||
for (const name in slots) {
|
for (const name in slots) {
|
||||||
|
if (name === STABLE_SLOTS_HINT) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
normalized[name] = (...args: any[]) => normalizeSlot(slots[name](...args))
|
normalized[name] = (...args: any[]) => normalizeSlot(slots[name](...args))
|
||||||
}
|
}
|
||||||
return normalized
|
return normalized
|
||||||
|
Loading…
Reference in New Issue
Block a user