From ebf980b555c0cbebea364ca84ddabdf49aa70f39 Mon Sep 17 00:00:00 2001 From: * <8> Date: Thu, 20 Jan 2022 15:59:54 +0800 Subject: [PATCH 1/4] Match-id-1335e3889f5c02b60f5677cb8bb35b2322310d6b --- libs/horizon/src/dom/SelectionRangeHandler.ts | 2 +- .../dom/valueHandler/ValueChangeHandler.ts | 6 +++--- libs/horizon/src/external/ChildrenUtil.ts | 1 - libs/horizon/src/renderer/TreeBuilder.ts | 4 ++-- libs/horizon/src/renderer/diff/DiffTools.ts | 2 +- .../src/renderer/hooks/UseEffectHook.ts | 4 ++-- .../src/renderer/render/LazyComponent.ts | 20 +++++++++---------- .../src/renderer/submit/LifeCycleHandler.ts | 4 ++-- libs/horizon/src/renderer/vnode/VNodeUtils.ts | 1 + 9 files changed, 22 insertions(+), 22 deletions(-) diff --git a/libs/horizon/src/dom/SelectionRangeHandler.ts b/libs/horizon/src/dom/SelectionRangeHandler.ts index d4f98942..8497984d 100644 --- a/libs/horizon/src/dom/SelectionRangeHandler.ts +++ b/libs/horizon/src/dom/SelectionRangeHandler.ts @@ -69,7 +69,7 @@ function isNodeContainsByTargetNode(targetNode, node) { return false; } -function isInDocument(dom) { +function isInDocument(dom): any | void { if (dom && dom.ownerDocument) { return isNodeContainsByTargetNode(dom.ownerDocument.documentElement, dom); } diff --git a/libs/horizon/src/dom/valueHandler/ValueChangeHandler.ts b/libs/horizon/src/dom/valueHandler/ValueChangeHandler.ts index 35d31e20..34406ef8 100644 --- a/libs/horizon/src/dom/valueHandler/ValueChangeHandler.ts +++ b/libs/horizon/src/dom/valueHandler/ValueChangeHandler.ts @@ -34,12 +34,12 @@ export function watchValueChange(dom) { // currentVal存储最新值,并重写value的setter、getter let currentVal = String(dom[keyForValue]); - const setFunc = descriptor.set; + const setFunc = descriptor?.set; Object.defineProperty(dom, keyForValue, { ...descriptor, - set: function (value) { + set: function(value) { currentVal = String(value); - setFunc.apply(this, [value]); + setFunc?.apply(this, [value]); }, }); diff --git a/libs/horizon/src/external/ChildrenUtil.ts b/libs/horizon/src/external/ChildrenUtil.ts index 179cf73e..9b35623f 100644 --- a/libs/horizon/src/external/ChildrenUtil.ts +++ b/libs/horizon/src/external/ChildrenUtil.ts @@ -47,7 +47,6 @@ function mapChildrenToArray( 'Object is invalid as a Horizon child. ' ); default: - return; } } diff --git a/libs/horizon/src/renderer/TreeBuilder.ts b/libs/horizon/src/renderer/TreeBuilder.ts index a628048b..55edba61 100644 --- a/libs/horizon/src/renderer/TreeBuilder.ts +++ b/libs/horizon/src/renderer/TreeBuilder.ts @@ -219,7 +219,7 @@ export function tryRenderRoot(treeRoot: VNode) { } // 发起更新 -export function launchUpdateFromVNode(vNode: VNode): null | void { +export function launchUpdateFromVNode(vNode: VNode): void { // 检查循环调用 checkLoopingUpdateLimit(); @@ -228,7 +228,7 @@ export function launchUpdateFromVNode(vNode: VNode): null | void { if (treeRoot === null) { // 可能场景是:the componentWillUnmount method 或 useEffect cleanup function 方法中写异步任务,并且修改state。 // 因为异步回调的时候root都可能被清除了。 - return null; + return; } // 保存待刷新的节点 diff --git a/libs/horizon/src/renderer/diff/DiffTools.ts b/libs/horizon/src/renderer/diff/DiffTools.ts index 928f889b..c2b44411 100644 --- a/libs/horizon/src/renderer/diff/DiffTools.ts +++ b/libs/horizon/src/renderer/diff/DiffTools.ts @@ -6,7 +6,7 @@ export const isSameType = (vNode: VNode, ele: HorizonElement) => { return vNode.type === ele.type || (vNode.isLazyComponent && vNode.lazyType === ele.type); }; -export function createRef(element: HorizonElement) { +export function createRef(element: HorizonElement): any | void { const elementRef = element.ref; // 如果ref是null、function、object,直接返回 if (elementRef === null || typeof elementRef === 'function' || typeof elementRef === 'object') { diff --git a/libs/horizon/src/renderer/hooks/UseEffectHook.ts b/libs/horizon/src/renderer/hooks/UseEffectHook.ts index ccd4e7d4..d3418782 100644 --- a/libs/horizon/src/renderer/hooks/UseEffectHook.ts +++ b/libs/horizon/src/renderer/hooks/UseEffectHook.ts @@ -31,9 +31,9 @@ function useEffect( } if (stage === HookStage.Init) { - return useEffectForInit(effectFunc, deps, effectType); + useEffectForInit(effectFunc, deps, effectType); } else if (stage === HookStage.Update) { - return useEffectForUpdate(effectFunc, deps, effectType); + useEffectForUpdate(effectFunc, deps, effectType); } } diff --git a/libs/horizon/src/renderer/render/LazyComponent.ts b/libs/horizon/src/renderer/render/LazyComponent.ts index 65f7285c..99e35353 100644 --- a/libs/horizon/src/renderer/render/LazyComponent.ts +++ b/libs/horizon/src/renderer/render/LazyComponent.ts @@ -1,23 +1,23 @@ -import type {VNode} from '../Types'; +import type { VNode } from '../Types'; -import {FlagUtils} from '../vnode/VNodeFlags'; -import {getLazyVNodeTag} from '../vnode/VNodeCreator'; +import { FlagUtils } from '../vnode/VNodeFlags'; +import { getLazyVNodeTag } from '../vnode/VNodeCreator'; import { ClassComponent, ForwardRef, FunctionComponent, MemoComponent, } from '../vnode/VNodeTags'; -import {throwIfTrue} from '../utils/throwIfTrue'; -import {captureFunctionComponent} from './FunctionComponent'; -import {captureClassComponent} from './ClassComponent'; -import {captureMemoComponent} from './MemoComponent'; +import { throwIfTrue } from '../utils/throwIfTrue'; +import { captureFunctionComponent } from './FunctionComponent'; +import { captureClassComponent } from './ClassComponent'; +import { captureMemoComponent } from './MemoComponent'; export function captureRender(processing: VNode, shouldUpdate: boolean): VNode | null { return captureLazyComponent(processing, processing.type, shouldUpdate); } -export function bubbleRender() {} +export function bubbleRender() { } const LazyRendererMap = { [FunctionComponent]: captureFunctionComponent, @@ -30,7 +30,7 @@ function captureLazyComponent( processing, lazyComponent, shouldUpdate, -) { +): any | void { if (!processing.isCreated) { // 每次加载lazy都当作mount来处理 processing.isCreated = true; @@ -69,7 +69,7 @@ function captureLazyComponent( export function mergeDefaultProps(Component: any, props: object): object { if (Component && Component.defaultProps) { - const clonedProps = {...props}; + const clonedProps = { ...props }; const defaultProps = Component.defaultProps; Object.keys(defaultProps).forEach(key => { if (clonedProps[key] === undefined) { diff --git a/libs/horizon/src/renderer/submit/LifeCycleHandler.ts b/libs/horizon/src/renderer/submit/LifeCycleHandler.ts index 779f3653..3c303192 100644 --- a/libs/horizon/src/renderer/submit/LifeCycleHandler.ts +++ b/libs/horizon/src/renderer/submit/LifeCycleHandler.ts @@ -70,8 +70,8 @@ function callBeforeSubmitLifeCycles( case TreeRoot: { const root = vNode.realNode; clearContainer(root.outerDom); - return; } + // No Default } } @@ -136,8 +136,8 @@ function callAfterSubmitLifeCycles( vNode.realNode.focus(); } } - return; } + //No Default } } diff --git a/libs/horizon/src/renderer/vnode/VNodeUtils.ts b/libs/horizon/src/renderer/vnode/VNodeUtils.ts index 0183dd67..3251cb7d 100644 --- a/libs/horizon/src/renderer/vnode/VNodeUtils.ts +++ b/libs/horizon/src/renderer/vnode/VNodeUtils.ts @@ -144,6 +144,7 @@ export function findDomVNode(vNode: VNode): VNode | null { if (node.tag === DomComponent || node.tag === DomText) { return node; } + return null; }); } From c66db8d84fc4a138b4478891354b37934f7a397a Mon Sep 17 00:00:00 2001 From: * <8> Date: Thu, 20 Jan 2022 16:59:09 +0800 Subject: [PATCH 2/4] Match-id-8d8e589bdbc4b167a6b0e61f1706aa51e83543e5 --- libs/horizon/src/dom/SelectionRangeHandler.ts | 3 ++- libs/horizon/src/external/ChildrenUtil.ts | 3 ++- libs/horizon/src/renderer/TreeBuilder.ts | 2 +- libs/horizon/src/renderer/render/LazyComponent.ts | 3 ++- libs/horizon/src/renderer/submit/LifeCycleHandler.ts | 4 +++- 5 files changed, 10 insertions(+), 5 deletions(-) diff --git a/libs/horizon/src/dom/SelectionRangeHandler.ts b/libs/horizon/src/dom/SelectionRangeHandler.ts index 8497984d..f5bde5bf 100644 --- a/libs/horizon/src/dom/SelectionRangeHandler.ts +++ b/libs/horizon/src/dom/SelectionRangeHandler.ts @@ -69,10 +69,11 @@ function isNodeContainsByTargetNode(targetNode, node) { return false; } -function isInDocument(dom): any | void { +function isInDocument(dom) { if (dom && dom.ownerDocument) { return isNodeContainsByTargetNode(dom.ownerDocument.documentElement, dom); } + return false; } // 判断一个标签是否有设置选择范围的能力 diff --git a/libs/horizon/src/external/ChildrenUtil.ts b/libs/horizon/src/external/ChildrenUtil.ts index 9b35623f..d46e217b 100644 --- a/libs/horizon/src/external/ChildrenUtil.ts +++ b/libs/horizon/src/external/ChildrenUtil.ts @@ -46,7 +46,8 @@ function mapChildrenToArray( throw new Error( 'Object is invalid as a Horizon child. ' ); - default: + + // No Default } } diff --git a/libs/horizon/src/renderer/TreeBuilder.ts b/libs/horizon/src/renderer/TreeBuilder.ts index 55edba61..0d3bfa9e 100644 --- a/libs/horizon/src/renderer/TreeBuilder.ts +++ b/libs/horizon/src/renderer/TreeBuilder.ts @@ -219,7 +219,7 @@ export function tryRenderRoot(treeRoot: VNode) { } // 发起更新 -export function launchUpdateFromVNode(vNode: VNode): void { +export function launchUpdateFromVNode(vNode: VNode) { // 检查循环调用 checkLoopingUpdateLimit(); diff --git a/libs/horizon/src/renderer/render/LazyComponent.ts b/libs/horizon/src/renderer/render/LazyComponent.ts index 99e35353..f3dcc954 100644 --- a/libs/horizon/src/renderer/render/LazyComponent.ts +++ b/libs/horizon/src/renderer/render/LazyComponent.ts @@ -30,7 +30,7 @@ function captureLazyComponent( processing, lazyComponent, shouldUpdate, -): any | void { +) { if (!processing.isCreated) { // 每次加载lazy都当作mount来处理 processing.isCreated = true; @@ -64,6 +64,7 @@ function captureLazyComponent( Component, '', ); + return null; } } diff --git a/libs/horizon/src/renderer/submit/LifeCycleHandler.ts b/libs/horizon/src/renderer/submit/LifeCycleHandler.ts index 3c303192..d2eafa4c 100644 --- a/libs/horizon/src/renderer/submit/LifeCycleHandler.ts +++ b/libs/horizon/src/renderer/submit/LifeCycleHandler.ts @@ -71,6 +71,7 @@ function callBeforeSubmitLifeCycles( const root = vNode.realNode; clearContainer(root.outerDom); } + // No Default } } @@ -137,7 +138,8 @@ function callAfterSubmitLifeCycles( } } } - //No Default + + // No Default } } From 10c8ee378680945c0b76ff6800c1f68184ad0b7e Mon Sep 17 00:00:00 2001 From: * <8> Date: Thu, 20 Jan 2022 18:14:44 +0800 Subject: [PATCH 3/4] Match-id-812ccb8a377f3e7902c60846555b0050c1f6d8bd --- libs/horizon/src/external/ChildrenUtil.ts | 81 +++++---- libs/horizon/src/external/HorizonElement.ts | 18 +- libs/horizon/src/renderer/Renderer.ts | 2 +- .../src/renderer/render/BaseComponent.ts | 51 +++--- .../src/renderer/render/ClassComponent.ts | 162 +++++++++--------- .../src/renderer/render/ClsOrFunComponent.ts | 14 +- .../src/renderer/render/ContextConsumer.ts | 13 +- .../src/renderer/render/ContextProvider.ts | 16 +- 8 files changed, 178 insertions(+), 179 deletions(-) diff --git a/libs/horizon/src/external/ChildrenUtil.ts b/libs/horizon/src/external/ChildrenUtil.ts index d46e217b..c1b681ad 100644 --- a/libs/horizon/src/external/ChildrenUtil.ts +++ b/libs/horizon/src/external/ChildrenUtil.ts @@ -12,45 +12,6 @@ function getItemKey(item: any, index: number): string { return '.' + index.toString(36); } -function mapChildrenToArray( - children: any, - arr: Array, - prefix: string, - callback?: Function, -): number | void { - const type = typeof children; - switch (type) { - // 继承原有规格,undefined和boolean类型按照null处理 - case 'undefined': - case 'boolean': - callMapFun(null, arr, prefix, callback); - return; - case 'number': - case 'string': - callMapFun(children, arr, prefix, callback); - return; - case 'object': - if (children === null) { - callMapFun(null, arr, prefix, callback); - return; - } - const vtype = children.vtype; - if (vtype === TYPE_ELEMENT || vtype === TYPE_PORTAL) { - callMapFun(children, arr, prefix, callback) ; - return; - } - if (Array.isArray(children)) { - processArrayChildren(children, arr, prefix, callback); - return; - } - throw new Error( - 'Object is invalid as a Horizon child. ' - ); - - // No Default - } -} - function processArrayChildren( children: any, arr: Array, @@ -100,6 +61,44 @@ function callMapFun( } } +function mapChildrenToArray( + children: any, + arr: Array, + prefix: string, + callback?: Function, +): number | void { + const type = typeof children; + switch (type) { + // 继承原有规格,undefined和boolean类型按照null处理 + case 'undefined': + case 'boolean': + callMapFun(null, arr, prefix, callback); + return; + case 'number': + case 'string': + callMapFun(children, arr, prefix, callback); + return; + case 'object': + if (children === null) { + callMapFun(null, arr, prefix, callback); + return; + } + const vtype = children.vtype; + if (vtype === TYPE_ELEMENT || vtype === TYPE_PORTAL) { + callMapFun(children, arr, prefix, callback) ; + return; + } + if (Array.isArray(children)) { + processArrayChildren(children, arr, prefix, callback); + return; + } + throw new Error( + 'Object is invalid as a Horizon child. ' + ); + // No Default + } +} + // 在 children 里的每个直接子节点上调用一个函数,并将 this 设置为 thisArg function mapChildren( children: any, @@ -111,9 +110,7 @@ function mapChildren( } let count = 0; const result = []; - mapChildrenToArray(children, result, '', (child) => { - return func.call(context, child, count++); - }); + mapChildrenToArray(children, result, '', child => func.call(context, child, count++)); return result; } diff --git a/libs/horizon/src/external/HorizonElement.ts b/libs/horizon/src/external/HorizonElement.ts index 186f343c..c315bd6a 100644 --- a/libs/horizon/src/external/HorizonElement.ts +++ b/libs/horizon/src/external/HorizonElement.ts @@ -23,12 +23,20 @@ export function HorizonElement(type, key, ref, vNode, props) { // 记录负责创建此元素的组件。 _vNode: vNode, }; -}; +} function isValidKey(key) { return key !== 'key' && key !== 'ref' && key !== '__source'; } +function mergeDefault(sourceObj, defaultObj) { + Object.keys(defaultObj).forEach((key) => { + if (sourceObj[key] === undefined) { + sourceObj[key] = defaultObj[key]; + } + }); +} + function buildElement(isClone, type, setting, ...children) { // setting中的值优先级最高,clone情况下从 type 中取值,创建情况下直接赋值为 null const key = (setting && setting.key !== undefined) ? String(setting.key) : (isClone ? type.key : null); @@ -64,14 +72,6 @@ export function createElement(type, setting, ...children) { return buildElement(false, type, setting, ...children); } -function mergeDefault(sourceObj, defaultObj) { - Object.keys(defaultObj).forEach((key) => { - if (sourceObj[key] === undefined) { - sourceObj[key] = defaultObj[key]; - } - }); -} - export function cloneElement(element, setting, ...children) { return buildElement(true, element, setting, ...children); } diff --git a/libs/horizon/src/renderer/Renderer.ts b/libs/horizon/src/renderer/Renderer.ts index ebf8da2b..32c3cc0f 100644 --- a/libs/horizon/src/renderer/Renderer.ts +++ b/libs/horizon/src/renderer/Renderer.ts @@ -37,7 +37,7 @@ export function startUpdate( launchUpdateFromVNode(treeRoot); } -export function getFirstCustomDom(treeRoot: VNode): Element | Text | null { +export function getFirstCustomDom(treeRoot: VNode | undefined | null): Element | Text | null { if (treeRoot?.child) { return treeRoot.child.realNode; } diff --git a/libs/horizon/src/renderer/render/BaseComponent.ts b/libs/horizon/src/renderer/render/BaseComponent.ts index b045b215..8e5e56d4 100644 --- a/libs/horizon/src/renderer/render/BaseComponent.ts +++ b/libs/horizon/src/renderer/render/BaseComponent.ts @@ -15,6 +15,32 @@ import { createChildrenByDiff } from '../diff/nodeDiffComparator'; import {onlyUpdateChildVNodes} from '../vnode/VNodeCreator'; import componentRenders from './index'; +// 复用vNode时,也需对stack进行处理 +function handlerContext(processing: VNode) { + switch (processing.tag) { + case TreeRoot: + setNamespaceCtx(processing, processing.outerDom); + break; + case DomComponent: + setNamespaceCtx(processing); + break; + case ClassComponent: { + const isOldCxtExist = isOldProvider(processing.type); + cacheOldCtx(processing, isOldCxtExist); + break; + } + case DomPortal: + setNamespaceCtx(processing, processing.outerDom); + break; + case ContextProvider: { + const newValue = processing.props.value; + setContextCtx(processing, newValue); + break; + } + // No Default + } +} + export function captureVNode(processing: VNode): VNode | null { const component = componentRenders[processing.tag]; @@ -38,31 +64,6 @@ export function captureVNode(processing: VNode): VNode | null { return component.captureRender(processing, shouldUpdate); } -// 复用vNode时,也需对stack进行处理 -function handlerContext(processing: VNode) { - switch (processing.tag) { - case TreeRoot: - setNamespaceCtx(processing, processing.outerDom); - break; - case DomComponent: - setNamespaceCtx(processing); - break; - case ClassComponent: { - const isOldCxtExist = isOldProvider(processing.type); - cacheOldCtx(processing, isOldCxtExist); - break; - } - case DomPortal: - setNamespaceCtx(processing, processing.outerDom); - break; - case ContextProvider: { - const newValue = processing.props.value; - setContextCtx(processing, newValue); - break; - } - } -} - // 创建孩子节点 export function createVNodeChildren(processing: VNode, nextChildren: any) { const isComparing = !processing.isCreated; diff --git a/libs/horizon/src/renderer/render/ClassComponent.ts b/libs/horizon/src/renderer/render/ClassComponent.ts index 72ff9224..2be13d49 100644 --- a/libs/horizon/src/renderer/render/ClassComponent.ts +++ b/libs/horizon/src/renderer/render/ClassComponent.ts @@ -20,7 +20,7 @@ import { markComponentDidUpdate, markGetSnapshotBeforeUpdate, } from './class/ClassLifeCycleProcessor'; -import {FlagUtils} from '../vnode/VNodeFlags'; +import { FlagUtils } from '../vnode/VNodeFlags'; import { createVNodeChildren, markRef } from './BaseComponent'; import { createUpdateArray, @@ -28,25 +28,80 @@ import { } from '../UpdateHandler'; import { getContextChangeCtx, setContextChangeCtx } from '../ContextSaver'; import ProcessingVNode from '../vnode/ProcessingVNode'; -import {onlyUpdateChildVNodes} from '../vnode/VNodeCreator'; +import { onlyUpdateChildVNodes } from '../vnode/VNodeCreator'; -export function captureRender(processing: VNode): VNode | null { - const clazz = processing.type; - const props = processing.props; - const nextProps = processing.isLazyComponent ? mergeDefaultProps(clazz, props) : props; - return captureClassComponent(processing, clazz, nextProps); +// 获取当前节点的context +export function getCurrentContext(clazz, processing: VNode) { + const context = clazz.contextType; + return typeof context === 'object' && context !== null + ? getNewContext(processing, context) + : getOldContext(processing, clazz, true); } -export function bubbleRender(processing: VNode) { - if (isOldProvider(processing.type)) { - resetOldCtx(processing); +// 挂载实例 +function mountInstance(clazz, processing: VNode, nextProps: object) { + if (!processing.isCreated) { + processing.isCreated = true; + FlagUtils.markAddition(processing); + } + + // 构造实例 + callConstructor(processing, clazz, nextProps); + + const inst = processing.realNode; + inst.props = nextProps; + inst.state = processing.state; + inst.context = getCurrentContext(clazz, processing); + inst.refs = {}; + + createUpdateArray(processing); + processUpdates(processing, inst, nextProps); + inst.state = processing.state; + + // 在调用类组建的渲染方法之前调用 并且在初始挂载及后续更新时都会被调用 + callDerivedStateFromProps(processing, clazz.getDerivedStateFromProps, nextProps); + callComponentWillMount(processing, inst, nextProps); + + markComponentDidMount(processing); +} + +// 构建子节点 +function createChildren(clazz: any, processing: VNode) { + markRef(processing); + + ProcessingVNode.val = processing; + processing.state = processing.realNode.state; + + const inst = processing.realNode; + const isCatchError = processing.flags.DidCapture; + + // 按照已有规格,如果捕获了错误却没有定义getDerivedStateFromError函数,返回的child为null + const newElements = isCatchError && typeof clazz.getDerivedStateFromError !== 'function' + ? null + : inst.render(); + + processing.child = createVNodeChildren(processing, newElements); + return processing.child; +} + +// 根据isUpdateComponent,执行不同的生命周期 +function callUpdateLifeCycle(processing: VNode, nextProps: object, clazz) { + const inst = processing.realNode; + const newContext = getCurrentContext(clazz, processing); + if (processing.isCreated) { + callComponentWillMount(processing, inst); + } else { + callComponentWillUpdate(inst, nextProps, processing.state, newContext); } } -// 用于未完成的类组件 -export function getIncompleteClassComponent(clazz, processing: VNode, nextProps: object):VNode | null { - mountInstance(clazz, processing, nextProps); - return createChildren(clazz, processing); +function markLifeCycle(processing: VNode, nextProps: object, shouldUpdate: Boolean) { + if (processing.isCreated) { + markComponentDidMount(processing); + } else if (processing.state !== processing.oldState || shouldUpdate) { + markComponentDidUpdate(processing); + markGetSnapshotBeforeUpdate(processing); + } } // 用于类组件 @@ -127,76 +182,21 @@ export function captureClassComponent(processing: VNode, clazz: any, nextProps: } } -// 挂载实例 -function mountInstance(clazz, processing: VNode, nextProps: object) { - if (!processing.isCreated) { - processing.isCreated = true; - FlagUtils.markAddition(processing); - } - - // 构造实例 - callConstructor(processing, clazz, nextProps); - - const inst = processing.realNode; - inst.props = nextProps; - inst.state = processing.state; - inst.context = getCurrentContext(clazz, processing); - inst.refs = {}; - - createUpdateArray(processing); - processUpdates(processing, inst, nextProps); - inst.state = processing.state; - - // 在调用类组建的渲染方法之前调用 并且在初始挂载及后续更新时都会被调用 - callDerivedStateFromProps(processing, clazz.getDerivedStateFromProps, nextProps); - callComponentWillMount(processing, inst, nextProps); - - markComponentDidMount(processing); +export function captureRender(processing: VNode): VNode | null { + const clazz = processing.type; + const props = processing.props; + const nextProps = processing.isLazyComponent ? mergeDefaultProps(clazz, props) : props; + return captureClassComponent(processing, clazz, nextProps); } -// 构建子节点 -function createChildren(clazz: any, processing: VNode) { - markRef(processing); - - ProcessingVNode.val = processing; - processing.state = processing.realNode.state; - - const inst = processing.realNode; - const isCatchError = processing.flags.DidCapture; - - // 按照已有规格,如果捕获了错误却没有定义getDerivedStateFromError函数,返回的child为null - const newElements = (isCatchError && typeof clazz.getDerivedStateFromError !== 'function') - ? null - : inst.render(); - - processing.child = createVNodeChildren(processing, newElements); - return processing.child; -} - -// 获取当前节点的context -export function getCurrentContext(clazz, processing: VNode) { - const context = clazz.contextType; - return typeof context === 'object' && context !== null - ? getNewContext(processing, context) - : getOldContext(processing, clazz, true); -} - -// 根据isUpdateComponent,执行不同的生命周期 -function callUpdateLifeCycle(processing: VNode, nextProps: object, clazz) { - const inst = processing.realNode; - const newContext = getCurrentContext(clazz, processing); - if (processing.isCreated) { - callComponentWillMount(processing, inst); - } else { - callComponentWillUpdate(inst, nextProps, processing.state, newContext); +export function bubbleRender(processing: VNode) { + if (isOldProvider(processing.type)) { + resetOldCtx(processing); } } -function markLifeCycle(processing: VNode, nextProps: object, shouldUpdate: Boolean) { - if (processing.isCreated) { - markComponentDidMount(processing); - } else if (processing.state !== processing.oldState || shouldUpdate) { - markComponentDidUpdate(processing); - markGetSnapshotBeforeUpdate(processing); - } +// 用于未完成的类组件 +export function getIncompleteClassComponent(clazz, processing: VNode, nextProps: object): VNode | null { + mountInstance(clazz, processing, nextProps); + return createChildren(clazz, processing); } diff --git a/libs/horizon/src/renderer/render/ClsOrFunComponent.ts b/libs/horizon/src/renderer/render/ClsOrFunComponent.ts index 4a2204a1..6eccd85b 100644 --- a/libs/horizon/src/renderer/render/ClsOrFunComponent.ts +++ b/libs/horizon/src/renderer/render/ClsOrFunComponent.ts @@ -7,14 +7,8 @@ import {FlagUtils} from '../vnode/VNodeFlags'; import {exeFunctionHook} from '../hooks/HookMain'; import {createVNodeChildren} from './BaseComponent'; -export function captureRender(processing: VNode): VNode | null { - return captureIndeterminateComponent(processing); -} - -export function bubbleRender() {} - function captureIndeterminateComponent( - processing: VNode | null, + processing: VNode, ): VNode | null { const funcComp = processing.type; @@ -34,3 +28,9 @@ function captureIndeterminateComponent( processing.child = createVNodeChildren(processing, newElements); return processing.child; } + +export function captureRender(processing: VNode): VNode | null { + return captureIndeterminateComponent(processing); +} + +export function bubbleRender() {} diff --git a/libs/horizon/src/renderer/render/ContextConsumer.ts b/libs/horizon/src/renderer/render/ContextConsumer.ts index 7fcbd59c..c45934db 100644 --- a/libs/horizon/src/renderer/render/ContextConsumer.ts +++ b/libs/horizon/src/renderer/render/ContextConsumer.ts @@ -3,12 +3,6 @@ import type {VNode, ContextType} from '../Types'; import {resetDepContexts, getNewContext} from '../components/context/Context'; import {createVNodeChildren} from './BaseComponent'; -export function captureRender(processing: VNode): VNode | null { - return captureContextConsumer(processing); -} - -export function bubbleRender() {} - function captureContextConsumer(processing: VNode) { const context: ContextType = processing.type; const props = processing.props; @@ -21,3 +15,10 @@ function captureContextConsumer(processing: VNode) { processing.child = createVNodeChildren(processing, newChildren); return processing.child; } + +export function captureRender(processing: VNode): VNode | null { + return captureContextConsumer(processing); +} + +export function bubbleRender() {} + diff --git a/libs/horizon/src/renderer/render/ContextProvider.ts b/libs/horizon/src/renderer/render/ContextProvider.ts index c0ef07e6..c60156c7 100644 --- a/libs/horizon/src/renderer/render/ContextProvider.ts +++ b/libs/horizon/src/renderer/render/ContextProvider.ts @@ -14,14 +14,6 @@ import {launchUpdateFromVNode} from '../TreeBuilder'; import {onlyUpdateChildVNodes} from '../vnode/VNodeCreator'; import {setParentsChildShouldUpdate} from '../vnode/VNodeShouldUpdate'; -export function captureRender(processing: VNode): VNode | null { - return captureContextProvider(processing); -} - -export function bubbleRender(processing: VNode) { - resetContextCtx(processing); -} - function captureContextProvider(processing: VNode): VNode | null { const providerType: ProviderType = processing.type; const contextType: ContextType = providerType._context; @@ -54,6 +46,14 @@ function captureContextProvider(processing: VNode): VNode | null { return processing.child; } +export function captureRender(processing: VNode): VNode | null { + return captureContextProvider(processing); +} + +export function bubbleRender(processing: VNode) { + resetContextCtx(processing); +} + // 从依赖中找到匹配context的VNode function matchDependencies(depContexts, context, vNode): boolean { for (let i = 0; i < depContexts.length; i++) { From 25c3a84991bd95fdd406026bf921a3212371dfcb Mon Sep 17 00:00:00 2001 From: * <8> Date: Fri, 21 Jan 2022 10:00:29 +0800 Subject: [PATCH 4/4] Match-id-dda58446000d7d98ad097c8e72465ec8e13cfe58 --- libs/horizon/src/renderer/Renderer.ts | 2 +- .../src/renderer/render/ContextProvider.ts | 52 +++++++++---------- 2 files changed, 27 insertions(+), 27 deletions(-) diff --git a/libs/horizon/src/renderer/Renderer.ts b/libs/horizon/src/renderer/Renderer.ts index 32c3cc0f..d5cf89da 100644 --- a/libs/horizon/src/renderer/Renderer.ts +++ b/libs/horizon/src/renderer/Renderer.ts @@ -37,7 +37,7 @@ export function startUpdate( launchUpdateFromVNode(treeRoot); } -export function getFirstCustomDom(treeRoot: VNode | undefined | null): Element | Text | null { +export function getFirstCustomDom(treeRoot?: VNode | null): Element | Text | null { if (treeRoot?.child) { return treeRoot.child.realNode; } diff --git a/libs/horizon/src/renderer/render/ContextProvider.ts b/libs/horizon/src/renderer/render/ContextProvider.ts index c60156c7..b980273c 100644 --- a/libs/horizon/src/renderer/render/ContextProvider.ts +++ b/libs/horizon/src/renderer/render/ContextProvider.ts @@ -14,6 +14,32 @@ import {launchUpdateFromVNode} from '../TreeBuilder'; import {onlyUpdateChildVNodes} from '../vnode/VNodeCreator'; import {setParentsChildShouldUpdate} from '../vnode/VNodeShouldUpdate'; +// 从当前子节点开始向下遍历,找到消费此context的组件,并更新 +function handleContextChange(processing: VNode, context: ContextType): void { + const vNode = processing.child; + if (vNode === null) { + return; + } + + let isMatch = false; + + // 从vNode开始遍历 + travelVNodeTree(vNode, (node) => { + const depContexts = node.depContexts; + if (depContexts.length) { + isMatch = matchDependencies(depContexts, context, node) ?? isMatch; + } + }, (node) => { + // 如果这是匹配的provider,则不要更深入地扫描 + return node.tag === ContextProvider && node.type === processing.type; + }, processing); + + // 找到了依赖context的子节点,触发一次更新 + if (isMatch) { + launchUpdateFromVNode(processing); + } +} + function captureContextProvider(processing: VNode): VNode | null { const providerType: ProviderType = processing.type; const contextType: ContextType = providerType._context; @@ -77,29 +103,3 @@ function matchDependencies(depContexts, context, vNode): boolean { return false; } - -// 从当前子节点开始向下遍历,找到消费此context的组件,并更新 -function handleContextChange(processing: VNode, context: ContextType): void { - const vNode = processing.child; - if (vNode === null) { - return; - } - - let isMatch = false; - - // 从vNode开始遍历 - travelVNodeTree(vNode, (node) => { - const depContexts = node.depContexts; - if (depContexts.length) { - isMatch = matchDependencies(depContexts, context, node) ?? isMatch; - } - }, (node) => { - // 如果这是匹配的provider,则不要更深入地扫描 - return node.tag === ContextProvider && node.type === processing.type; - }, processing); - - // 找到了依赖context的子节点,触发一次更新 - if (isMatch) { - launchUpdateFromVNode(processing); - } -}