vue3-yuanma/packages/runtime-core/src/componentRenderUtils.ts

112 lines
3.1 KiB
TypeScript
Raw Normal View History

2019-09-07 00:58:31 +08:00
import {
ComponentInternalInstance,
FunctionalComponent,
Data
} from './component'
import { VNode, normalizeVNode, createVNode, Comment } from './vnode'
2019-09-06 23:25:11 +08:00
import { ShapeFlags } from './shapeFlags'
2019-09-07 00:58:31 +08:00
import { handleError, ErrorCodes } from './errorHandling'
import { PatchFlags } from '@vue/shared'
2019-09-06 23:25:11 +08:00
// mark the current rendering instance for asset resolution (e.g.
// resolveComponent, resolveDirective) during render
2019-09-07 00:58:31 +08:00
export let currentRenderingInstance: ComponentInternalInstance | null = null
2019-09-06 23:25:11 +08:00
2019-09-07 00:58:31 +08:00
export function renderComponentRoot(
instance: ComponentInternalInstance
): VNode {
2019-09-06 23:25:11 +08:00
const {
type: Component,
vnode,
renderProxy,
props,
slots,
attrs,
emit
} = instance
let result
currentRenderingInstance = instance
try {
if (vnode.shapeFlag & ShapeFlags.STATEFUL_COMPONENT) {
result = normalizeVNode((instance.render as Function).call(renderProxy))
} else {
// functional
const render = Component as FunctionalComponent
result = normalizeVNode(
render.length > 1
? render(props, {
attrs,
slots,
emit
})
: render(props, null as any)
)
}
} catch (err) {
2019-09-07 00:58:31 +08:00
handleError(err, instance, ErrorCodes.RENDER_FUNCTION)
result = createVNode(Comment)
2019-09-06 23:25:11 +08:00
}
currentRenderingInstance = null
return result
}
export function shouldUpdateComponent(
prevVNode: VNode,
nextVNode: VNode,
optimized?: boolean
): boolean {
const { props: prevProps, children: prevChildren } = prevVNode
const { props: nextProps, children: nextChildren, patchFlag } = nextVNode
if (patchFlag > 0) {
2019-09-06 23:25:11 +08:00
if (patchFlag & PatchFlags.DYNAMIC_SLOTS) {
// slot content that references values that might have changed,
// e.g. in a v-for
return true
}
if (patchFlag & PatchFlags.FULL_PROPS) {
// presence of this flag indicates props are always non-null
return hasPropsChanged(prevProps as Data, nextProps as Data)
} else if (patchFlag & PatchFlags.PROPS) {
const dynamicProps = nextVNode.dynamicProps as string[]
for (let i = 0; i < dynamicProps.length; i++) {
const key = dynamicProps[i]
if ((nextProps as any)[key] !== (prevProps as any)[key]) {
return true
}
}
}
} else if (!optimized) {
// this path is only taken by manually written render functions
// so presence of any children leads to a forced update
if (prevChildren != null || nextChildren != null) {
return true
}
if (prevProps === nextProps) {
return false
}
if (prevProps === null) {
return nextProps !== null
}
if (nextProps === null) {
return prevProps !== null
}
return hasPropsChanged(prevProps, nextProps)
}
return false
}
function hasPropsChanged(prevProps: Data, nextProps: Data): boolean {
const nextKeys = Object.keys(nextProps)
if (nextKeys.length !== Object.keys(prevProps).length) {
return true
}
for (let i = 0; i < nextKeys.length; i++) {
const key = nextKeys[i]
if (nextProps[key] !== prevProps[key]) {
return true
}
}
return false
}