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 { RenderProxyHandlers, ComponentRenderProxy } from './componentProxy' | ||||
| import { ComponentPropsOptions } from './componentProps' | ||||
| import { Slots } from './componentSlots' | ||||
| import { PatchFlags } from './patchFlags' | ||||
| import { ShapeFlags } from './shapeFlags' | ||||
| import { warn } from './warning' | ||||
| import { | ||||
|   ErrorTypes, | ||||
|   handleError, | ||||
|   callWithErrorHandling, | ||||
|   callWithAsyncErrorHandling | ||||
| } from './errorHandling' | ||||
| import { AppContext, createAppContext } from './apiApp' | ||||
| import { Directive } from './directives' | ||||
| import { | ||||
|   applyOptions, | ||||
|   resolveAsset, | ||||
|   ComponentOptions | ||||
| } from './componentOptions' | ||||
| import { applyOptions, ComponentOptions } from './componentOptions' | ||||
| import { | ||||
|   EMPTY_OBJ, | ||||
|   isFunction, | ||||
| @ -309,109 +302,3 @@ function createSetupContext(instance: ComponentInstance): SetupContext { | ||||
|   } as any | ||||
|   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 { | ||||
|   ComponentInstance, | ||||
|   Data, | ||||
|   currentRenderingInstance, | ||||
|   currentInstance, | ||||
|   Component, | ||||
|   SetupContext | ||||
| @ -35,6 +34,7 @@ import { ComponentPropsOptions, ExtractPropTypes } from './componentProps' | ||||
| import { Directive } from './directives' | ||||
| import { VNodeChild } from './vnode' | ||||
| import { ComponentRenderProxy } from './componentProxy' | ||||
| import { currentRenderingInstance } from './componentRenderUtils' | ||||
| 
 | ||||
| interface ComponentOptionsBase< | ||||
|   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 | ||||
|   if (instance) { | ||||
|     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' | ||||
| import { | ||||
|   ComponentInstance, | ||||
|   renderComponentRoot, | ||||
|   shouldUpdateComponent, | ||||
|   createComponentInstance, | ||||
|   setupStatefulComponent | ||||
| } from './component' | ||||
| import { | ||||
|   renderComponentRoot, | ||||
|   shouldUpdateComponent | ||||
| } from './componentRenderUtils' | ||||
| import { | ||||
|   isString, | ||||
|   EMPTY_OBJ, | ||||
|  | ||||
| @ -14,10 +14,10 @@ return applyDirectives(h(comp), [ | ||||
| import { VNode, cloneVNode } from './vnode' | ||||
| import { extend, isArray, isFunction } from '@vue/shared' | ||||
| import { warn } from './warning' | ||||
| import { ComponentInstance, currentRenderingInstance } from './component' | ||||
| import { ComponentInstance } from './component' | ||||
| import { currentRenderingInstance } from './componentRenderUtils' | ||||
| import { callWithAsyncErrorHandling, ErrorTypes } from './errorHandling' | ||||
| import { HostNode } from './createRenderer' | ||||
| import { resolveAsset } from './componentOptions' | ||||
| import { ComponentRenderProxy } from './componentProxy' | ||||
| 
 | ||||
| export interface DirectiveBinding { | ||||
| @ -133,7 +133,3 @@ export function invokeDirectiveHook( | ||||
|     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 | ||||
| } from './errorHandling' | ||||
| 
 | ||||
| // For the compiler
 | ||||
| export { resolveComponent } from './component' | ||||
| export { applyDirectives, resolveDirective } from './directives' | ||||
| // For compiler generated code
 | ||||
| export { applyDirectives } from './directives' | ||||
| export { resolveComponent, resolveDirective } from './componentOptions' | ||||
| 
 | ||||
| // Types -----------------------------------------------------------------------
 | ||||
| 
 | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user