refactor: split componentRenderUtils
This commit is contained in:
parent
0f25c29119
commit
d87bed0138
@ -1,24 +1,17 @@
|
|||||||
import { VNode, normalizeVNode, VNodeChild, createVNode, Empty } from './vnode'
|
import { VNode, VNodeChild } from './vnode'
|
||||||
import { ReactiveEffect, reactive, readonly } from '@vue/reactivity'
|
import { ReactiveEffect, reactive, readonly } from '@vue/reactivity'
|
||||||
import { RenderProxyHandlers, ComponentRenderProxy } from './componentProxy'
|
import { RenderProxyHandlers, ComponentRenderProxy } from './componentProxy'
|
||||||
import { ComponentPropsOptions } from './componentProps'
|
import { ComponentPropsOptions } from './componentProps'
|
||||||
import { Slots } from './componentSlots'
|
import { Slots } from './componentSlots'
|
||||||
import { PatchFlags } from './patchFlags'
|
|
||||||
import { ShapeFlags } from './shapeFlags'
|
|
||||||
import { warn } from './warning'
|
import { warn } from './warning'
|
||||||
import {
|
import {
|
||||||
ErrorTypes,
|
ErrorTypes,
|
||||||
handleError,
|
|
||||||
callWithErrorHandling,
|
callWithErrorHandling,
|
||||||
callWithAsyncErrorHandling
|
callWithAsyncErrorHandling
|
||||||
} from './errorHandling'
|
} from './errorHandling'
|
||||||
import { AppContext, createAppContext } from './apiApp'
|
import { AppContext, createAppContext } from './apiApp'
|
||||||
import { Directive } from './directives'
|
import { Directive } from './directives'
|
||||||
import {
|
import { applyOptions, ComponentOptions } from './componentOptions'
|
||||||
applyOptions,
|
|
||||||
resolveAsset,
|
|
||||||
ComponentOptions
|
|
||||||
} from './componentOptions'
|
|
||||||
import {
|
import {
|
||||||
EMPTY_OBJ,
|
EMPTY_OBJ,
|
||||||
isFunction,
|
isFunction,
|
||||||
@ -309,109 +302,3 @@ function createSetupContext(instance: ComponentInstance): SetupContext {
|
|||||||
} as any
|
} as any
|
||||||
return __DEV__ ? Object.freeze(context) : context
|
return __DEV__ ? Object.freeze(context) : context
|
||||||
}
|
}
|
||||||
|
|
||||||
// mark the current rendering instance for asset resolution (e.g.
|
|
||||||
// resolveComponent, resolveDirective) during render
|
|
||||||
export let currentRenderingInstance: ComponentInstance | null = null
|
|
||||||
|
|
||||||
export function renderComponentRoot(instance: ComponentInstance): VNode {
|
|
||||||
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 RenderFunction).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) {
|
|
||||||
handleError(err, instance, ErrorTypes.RENDER_FUNCTION)
|
|
||||||
result = createVNode(Empty)
|
|
||||||
}
|
|
||||||
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) {
|
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
export function resolveComponent(name: string): Component | undefined {
|
|
||||||
return resolveAsset('components', name) as any
|
|
||||||
}
|
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
import {
|
import {
|
||||||
ComponentInstance,
|
ComponentInstance,
|
||||||
Data,
|
Data,
|
||||||
currentRenderingInstance,
|
|
||||||
currentInstance,
|
currentInstance,
|
||||||
Component,
|
Component,
|
||||||
SetupContext
|
SetupContext
|
||||||
@ -35,6 +34,7 @@ import { ComponentPropsOptions, ExtractPropTypes } from './componentProps'
|
|||||||
import { Directive } from './directives'
|
import { Directive } from './directives'
|
||||||
import { VNodeChild } from './vnode'
|
import { VNodeChild } from './vnode'
|
||||||
import { ComponentRenderProxy } from './componentProxy'
|
import { ComponentRenderProxy } from './componentProxy'
|
||||||
|
import { currentRenderingInstance } from './componentRenderUtils'
|
||||||
|
|
||||||
interface ComponentOptionsBase<
|
interface ComponentOptionsBase<
|
||||||
Props,
|
Props,
|
||||||
@ -385,7 +385,15 @@ function applyMixins(instance: ComponentInstance, mixins: ComponentOptions[]) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function resolveAsset(type: 'components' | 'directives', name: string) {
|
export function resolveComponent(name: string): Component | undefined {
|
||||||
|
return resolveAsset('components', name) as any
|
||||||
|
}
|
||||||
|
|
||||||
|
export function resolveDirective(name: string): Directive | undefined {
|
||||||
|
return resolveAsset('directives', name) as any
|
||||||
|
}
|
||||||
|
|
||||||
|
function resolveAsset(type: 'components' | 'directives', name: string) {
|
||||||
const instance = currentRenderingInstance || currentInstance
|
const instance = currentRenderingInstance || currentInstance
|
||||||
if (instance) {
|
if (instance) {
|
||||||
let camelized
|
let camelized
|
||||||
|
105
packages/runtime-core/src/componentRenderUtils.ts
Normal file
105
packages/runtime-core/src/componentRenderUtils.ts
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
import { ComponentInstance, FunctionalComponent, Data } from './component'
|
||||||
|
import { VNode, normalizeVNode, createVNode, Empty } from './vnode'
|
||||||
|
import { ShapeFlags } from './shapeFlags'
|
||||||
|
import { handleError, ErrorTypes } from './errorHandling'
|
||||||
|
import { PatchFlags } from './patchFlags'
|
||||||
|
|
||||||
|
// mark the current rendering instance for asset resolution (e.g.
|
||||||
|
// resolveComponent, resolveDirective) during render
|
||||||
|
export let currentRenderingInstance: ComponentInstance | null = null
|
||||||
|
|
||||||
|
export function renderComponentRoot(instance: ComponentInstance): VNode {
|
||||||
|
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) {
|
||||||
|
handleError(err, instance, ErrorTypes.RENDER_FUNCTION)
|
||||||
|
result = createVNode(Empty)
|
||||||
|
}
|
||||||
|
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) {
|
||||||
|
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
|
||||||
|
}
|
@ -9,11 +9,13 @@ import {
|
|||||||
} from './vnode'
|
} from './vnode'
|
||||||
import {
|
import {
|
||||||
ComponentInstance,
|
ComponentInstance,
|
||||||
renderComponentRoot,
|
|
||||||
shouldUpdateComponent,
|
|
||||||
createComponentInstance,
|
createComponentInstance,
|
||||||
setupStatefulComponent
|
setupStatefulComponent
|
||||||
} from './component'
|
} from './component'
|
||||||
|
import {
|
||||||
|
renderComponentRoot,
|
||||||
|
shouldUpdateComponent
|
||||||
|
} from './componentRenderUtils'
|
||||||
import {
|
import {
|
||||||
isString,
|
isString,
|
||||||
EMPTY_OBJ,
|
EMPTY_OBJ,
|
||||||
|
@ -14,10 +14,10 @@ return applyDirectives(h(comp), [
|
|||||||
import { VNode, cloneVNode } from './vnode'
|
import { VNode, cloneVNode } from './vnode'
|
||||||
import { extend, isArray, isFunction } from '@vue/shared'
|
import { extend, isArray, isFunction } from '@vue/shared'
|
||||||
import { warn } from './warning'
|
import { warn } from './warning'
|
||||||
import { ComponentInstance, currentRenderingInstance } from './component'
|
import { ComponentInstance } from './component'
|
||||||
|
import { currentRenderingInstance } from './componentRenderUtils'
|
||||||
import { callWithAsyncErrorHandling, ErrorTypes } from './errorHandling'
|
import { callWithAsyncErrorHandling, ErrorTypes } from './errorHandling'
|
||||||
import { HostNode } from './createRenderer'
|
import { HostNode } from './createRenderer'
|
||||||
import { resolveAsset } from './componentOptions'
|
|
||||||
import { ComponentRenderProxy } from './componentProxy'
|
import { ComponentRenderProxy } from './componentProxy'
|
||||||
|
|
||||||
export interface DirectiveBinding {
|
export interface DirectiveBinding {
|
||||||
@ -133,7 +133,3 @@ export function invokeDirectiveHook(
|
|||||||
callWithAsyncErrorHandling(hook, instance, ErrorTypes.DIRECTIVE_HOOK, args)
|
callWithAsyncErrorHandling(hook, instance, ErrorTypes.DIRECTIVE_HOOK, args)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function resolveDirective(name: string): Directive | undefined {
|
|
||||||
return resolveAsset('directives', name) as any
|
|
||||||
}
|
|
||||||
|
@ -36,9 +36,9 @@ export {
|
|||||||
callWithAsyncErrorHandling
|
callWithAsyncErrorHandling
|
||||||
} from './errorHandling'
|
} from './errorHandling'
|
||||||
|
|
||||||
// For the compiler
|
// For compiler generated code
|
||||||
export { resolveComponent } from './component'
|
export { applyDirectives } from './directives'
|
||||||
export { applyDirectives, resolveDirective } from './directives'
|
export { resolveComponent, resolveDirective } from './componentOptions'
|
||||||
|
|
||||||
// Types -----------------------------------------------------------------------
|
// Types -----------------------------------------------------------------------
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user