diff --git a/libs/horizon/src/dom/DOMOperator.ts b/libs/horizon/src/dom/DOMOperator.ts index 169e85b2..bb061fa7 100644 --- a/libs/horizon/src/dom/DOMOperator.ts +++ b/libs/horizon/src/dom/DOMOperator.ts @@ -110,7 +110,7 @@ export function getPropChangeList( type: string, lastRawProps: Props, nextRawProps: Props, -): Array { +): Map { // 校验两个对象的不同 validateProps(type, nextRawProps); @@ -123,11 +123,11 @@ export function getPropChangeList( } export function isTextChild(type: string, props: Props): boolean { - const typeArray = ['textarea', 'option', 'noscript']; - const typeOfPropsChild = ['string', 'number']; - if (typeArray.indexOf(type) >= 0) { + if (type === 'textarea' || type === 'option' || type === 'noscript') { return true; - } else if (typeOfPropsChild.indexOf(typeof props.children) >= 0) { + } + const childType = typeof props.children; + if (childType === 'string' || childType === 'number') { return true; } else { return ( diff --git a/libs/horizon/src/dom/DOMPropertiesHandler/DOMPropertiesHandler.ts b/libs/horizon/src/dom/DOMPropertiesHandler/DOMPropertiesHandler.ts index d0755511..496d0c2c 100644 --- a/libs/horizon/src/dom/DOMPropertiesHandler/DOMPropertiesHandler.ts +++ b/libs/horizon/src/dom/DOMPropertiesHandler/DOMPropertiesHandler.ts @@ -52,15 +52,10 @@ export function setDomProps( // 更新 DOM 属性 export function updateDomProps( dom: Element, - changeList: Array, + changeList: Map, isNativeTag: boolean, ): void { - const listLength = changeList.length; - let propName; - let propVal; - for (let i = 0; i < listLength; i++) { - propName = changeList[i].propName; - propVal = changeList[i].propVal; + for(const [propName, propVal] of changeList) { updateOneProp(dom, propName, isNativeTag, propVal); } } @@ -69,10 +64,9 @@ export function updateDomProps( export function compareProps( oldProps: Object, newProps: Object, -): Array { +): Map { let updatesForStyle = {}; - const toBeDeletedProps: Array = []; - const toBeUpdatedProps: Array = []; + const toUpdateProps = new Map(); const keysOfOldProps = Object.keys(oldProps); const keysOfNewProps = Object.keys(newProps); @@ -104,17 +98,11 @@ export function compareProps( continue; } else if (isEventProp(propName)) { if (!allDelegatedHorizonEvents.has(propName)) { - toBeDeletedProps.push({ - propName, - propVal: null, - }); + toUpdateProps.set(propName, null); } } else { // 其它属性都要加入到删除队列里面,等待删除 - toBeDeletedProps.push({ - propName, - propVal: null, - }); + toUpdateProps.set(propName, null); } } @@ -156,10 +144,7 @@ export function compareProps( } } else { // 之前未设置 style 属性或者设置了空值 if (Object.keys(updatesForStyle).length === 0) { - toBeUpdatedProps.push({ - propName, - propVal: null, - }); + toUpdateProps.set(propName, null); } updatesForStyle = newPropValue; } @@ -168,41 +153,26 @@ export function compareProps( oldHTML = oldPropValue ? oldPropValue.__html : undefined; if (newHTML != null) { if (oldHTML !== newHTML) { - toBeUpdatedProps.push({ - propName, - propVal: newPropValue, - }); + toUpdateProps.set(propName, newPropValue); } } } else if (propName === 'children') { if (typeof newPropValue === 'string' || typeof newPropValue === 'number') { - toBeUpdatedProps.push({ - propName, - propVal: String(newPropValue), - }); + toUpdateProps.set(propName, String(newPropValue)); } } else if (isEventProp(propName)) { if (!allDelegatedHorizonEvents.has(propName)) { - toBeUpdatedProps.push({ - propName, - propVal: newPropValue, - }); + toUpdateProps.set(propName, newPropValue); } } else { - toBeUpdatedProps.push({ - propName, - propVal: newPropValue, - }); + toUpdateProps.set(propName, newPropValue); } } // 处理style if (Object.keys(updatesForStyle).length > 0) { - toBeUpdatedProps.push({ - propName: 'style', - propVal: updatesForStyle, - }); + toUpdateProps.set('style', updatesForStyle); } - return [...toBeDeletedProps, ...toBeUpdatedProps]; + return toUpdateProps; } diff --git a/libs/horizon/src/renderer/components/BaseClassComponent.ts b/libs/horizon/src/renderer/components/BaseClassComponent.ts index ec141650..74f6df80 100644 --- a/libs/horizon/src/renderer/components/BaseClassComponent.ts +++ b/libs/horizon/src/renderer/components/BaseClassComponent.ts @@ -4,7 +4,10 @@ class Component { props: P; context: C; - state: S; + state: S | null; + refs: any; + setState: any; + forceUpdate: any; constructor(props: P, context: C) { this.props = props; diff --git a/libs/horizon/src/renderer/diff/nodeDiffComparator.ts b/libs/horizon/src/renderer/diff/nodeDiffComparator.ts index 530e9f87..d3033570 100644 --- a/libs/horizon/src/renderer/diff/nodeDiffComparator.ts +++ b/libs/horizon/src/renderer/diff/nodeDiffComparator.ts @@ -2,7 +2,7 @@ import type { VNode } from '../Types'; import { FlagUtils } from '../vnode/VNodeFlags'; import { TYPE_COMMON_ELEMENT, TYPE_FRAGMENT, TYPE_PORTAL } from '../../external/JSXElementType'; import { DomText, DomPortal, Fragment, DomComponent } from '../vnode/VNodeTags'; -import {updateVNode, createVNodeFromElement, updateVNodePath, createFragmentVNode, createPortalVNode, createDomTextVNode} from '../vnode/VNodeCreator'; +import {updateVNode, createVNodeFromElement, createFragmentVNode, createPortalVNode, createDomTextVNode} from '../vnode/VNodeCreator'; import { isSameType, getIteratorFn, @@ -209,11 +209,6 @@ function getOldNodeFromMap(nodeMap: Map, newIdx: number, return null; } -function setCIndex(vNode: VNode, idx: number) { - vNode.cIndex = idx; - updateVNodePath(vNode); -} - // diff数组类型的节点,核心算法 function diffArrayNodesHandler( parentNode: VNode, @@ -274,7 +269,8 @@ function diffArrayNodesHandler( theLastPosition = setVNodeAdditionFlag(newNode, theLastPosition, isComparing); newNode.eIndex = leftIdx; - setCIndex(newNode, leftIdx); + newNode.cIndex = leftIdx; + newNode.path = newNode.parent.path + newNode.cIndex; appendNode(newNode); oldNode = nextOldNode; } @@ -347,11 +343,23 @@ function diffArrayNodesHandler( // 4. 新节点还有一部分,但是老节点已经没有了 if (oldNode === null) { + + let isDirectAdd = false; + // TODO: 是否可以扩大至非dom类型节点 + // 如果dom节点在上次添加前没有节点,说明本次添加时,可以直接添加到最后,不需要通过 getSiblingDom 函数找到 before 节点 + if (parentNode.tag === DomComponent && parentNode.oldProps?.children?.length === 0 && rightIdx - leftIdx === newChildren.length) { + isDirectAdd = true; + } for (; leftIdx < rightIdx; leftIdx++) { newNode = getNewNode(parentNode, newChildren[leftIdx], null); if (newNode !== null) { - theLastPosition = setVNodeAdditionFlag(newNode, theLastPosition, isComparing); + if (isComparing) { + FlagUtils.setAddition(newNode); + } + if (isDirectAdd) { + FlagUtils.markDirectAddition(newNode); + } newNode.eIndex = leftIdx; appendNode(newNode); } @@ -460,7 +468,7 @@ function setVNodesCIndex(startChild: VNode, startIdx: number) { while (node !== null) { node.cIndex = idx; - updateVNodePath(node); + node.path = node.parent.path + node.cIndex; node = node.next; idx++; } @@ -471,7 +479,7 @@ function diffIteratorNodesHandler( parentNode: VNode, firstChild: VNode | null, newChildrenIterable: Iterable, - isComparing: boolean = true + isComparing: boolean ): VNode | null { const iteratorFn = getIteratorFn(newChildrenIterable); const iteratorObj = iteratorFn.call(newChildrenIterable); @@ -511,7 +519,7 @@ function diffStringNodeHandler( } newTextNode.parent = parentNode; newTextNode.cIndex = 0; - updateVNodePath(newTextNode); + newTextNode.path = newTextNode.parent.path + newTextNode.cIndex; return newTextNode; } @@ -589,7 +597,7 @@ function diffObjectNodeHandler( resultNode.parent = parentNode; resultNode.cIndex = 0; - updateVNodePath(resultNode); + resultNode.path = resultNode.parent.path + resultNode.cIndex; if (startDelVNode) { deleteVNodes(parentNode, startDelVNode); } @@ -604,7 +612,7 @@ export function createChildrenByDiff( parentNode: VNode, firstChild: VNode | null, newChild: any, - isComparing: boolean = true + isComparing: boolean ): VNode | null { const isFragment = isNoKeyFragment(newChild); newChild = isFragment ? newChild.props.children : newChild; diff --git a/libs/horizon/src/renderer/render/BaseComponent.ts b/libs/horizon/src/renderer/render/BaseComponent.ts index 1b2edf2d..afedf488 100644 --- a/libs/horizon/src/renderer/render/BaseComponent.ts +++ b/libs/horizon/src/renderer/render/BaseComponent.ts @@ -11,7 +11,6 @@ import { } from '../vnode/VNodeTags'; import { getContextChangeCtx, setContextCtx, setNamespaceCtx } from '../ContextSaver'; import { FlagUtils } from '../vnode/VNodeFlags'; -import { createChildrenByDiff } from '../diff/nodeDiffComparator'; import {onlyUpdateChildVNodes} from '../vnode/VNodeCreator'; import componentRenders from './index'; @@ -64,11 +63,6 @@ export function captureVNode(processing: VNode): VNode | null { return component.captureRender(processing, shouldUpdate); } -// 创建孩子节点 -export function createVNodeChildren(processing: VNode, nextChildren: any) { - return createChildrenByDiff(processing, processing.child, nextChildren, !processing.isCreated); -} - export function markRef(processing: VNode) { const ref = processing.ref; if ((processing.isCreated && ref !== null) || (!processing.isCreated && processing.oldRef !== ref)) { diff --git a/libs/horizon/src/renderer/render/ClassComponent.ts b/libs/horizon/src/renderer/render/ClassComponent.ts index 9c4c1f20..261fea3f 100644 --- a/libs/horizon/src/renderer/render/ClassComponent.ts +++ b/libs/horizon/src/renderer/render/ClassComponent.ts @@ -21,7 +21,7 @@ import { markGetSnapshotBeforeUpdate, } from './class/ClassLifeCycleProcessor'; import { FlagUtils, DidCapture } from '../vnode/VNodeFlags'; -import { createVNodeChildren, markRef } from './BaseComponent'; +import { markRef } from './BaseComponent'; import { createUpdateArray, processUpdates, @@ -29,6 +29,7 @@ import { import { getContextChangeCtx, setContextChangeCtx } from '../ContextSaver'; import { setProcessingClassVNode } from '../GlobalVar'; import { onlyUpdateChildVNodes } from '../vnode/VNodeCreator'; +import { createChildrenByDiff } from '../diff/nodeDiffComparator'; // 获取当前节点的context export function getCurrentContext(clazz, processing: VNode) { @@ -80,7 +81,7 @@ function createChildren(clazz: any, processing: VNode) { ? null : inst.render(); - processing.child = createVNodeChildren(processing, newElements); + processing.child = createChildrenByDiff(processing, processing.child, newElements, !processing.isCreated); return processing.child; } diff --git a/libs/horizon/src/renderer/render/ClsOrFunComponent.ts b/libs/horizon/src/renderer/render/ClsOrFunComponent.ts index 6eccd85b..fd342fac 100644 --- a/libs/horizon/src/renderer/render/ClsOrFunComponent.ts +++ b/libs/horizon/src/renderer/render/ClsOrFunComponent.ts @@ -5,7 +5,7 @@ import {resetDepContexts} from '../components/context/Context'; import {getOldContext} from '../components/context/CompatibleContext'; import {FlagUtils} from '../vnode/VNodeFlags'; import {exeFunctionHook} from '../hooks/HookMain'; -import {createVNodeChildren} from './BaseComponent'; +import { createChildrenByDiff } from '../diff/nodeDiffComparator'; function captureIndeterminateComponent( processing: VNode, @@ -25,7 +25,7 @@ function captureIndeterminateComponent( const newElements = exeFunctionHook(funcComp, props, context, processing); processing.tag = FunctionComponent; - processing.child = createVNodeChildren(processing, newElements); + processing.child = createChildrenByDiff(processing, processing.child, newElements, !processing.isCreated); return processing.child; } diff --git a/libs/horizon/src/renderer/render/ContextConsumer.ts b/libs/horizon/src/renderer/render/ContextConsumer.ts index c45934db..15e6c2d4 100644 --- a/libs/horizon/src/renderer/render/ContextConsumer.ts +++ b/libs/horizon/src/renderer/render/ContextConsumer.ts @@ -1,7 +1,7 @@ import type {VNode, ContextType} from '../Types'; import {resetDepContexts, getNewContext} from '../components/context/Context'; -import {createVNodeChildren} from './BaseComponent'; +import { createChildrenByDiff } from '../diff/nodeDiffComparator'; function captureContextConsumer(processing: VNode) { const context: ContextType = processing.type; @@ -12,7 +12,7 @@ function captureContextConsumer(processing: VNode) { const contextVal = getNewContext(processing, context); const newChildren = renderFunc(contextVal); - processing.child = createVNodeChildren(processing, newChildren); + processing.child = createChildrenByDiff(processing, processing.child, newChildren, !processing.isCreated); return processing.child; } diff --git a/libs/horizon/src/renderer/render/ContextProvider.ts b/libs/horizon/src/renderer/render/ContextProvider.ts index c3c287d8..24aaa9f4 100644 --- a/libs/horizon/src/renderer/render/ContextProvider.ts +++ b/libs/horizon/src/renderer/render/ContextProvider.ts @@ -1,18 +1,18 @@ -import type {VNode, ContextType, ProviderType} from '../Types'; +import type { VNode, ContextType, ProviderType } from '../Types'; -import {createVNodeChildren} from './BaseComponent'; -import {isSame} from '../utils/compare'; -import {ClassComponent, ContextProvider} from '../vnode/VNodeTags'; -import {pushForceUpdate} from '../UpdateHandler'; +import { isSame } from '../utils/compare'; +import { ClassComponent, ContextProvider } from '../vnode/VNodeTags'; +import { pushForceUpdate } from '../UpdateHandler'; import { getContextChangeCtx, resetContextCtx, setContextCtx, } from '../ContextSaver'; -import {getFirstChild, travelVNodeTree} from '../vnode/VNodeUtils'; -import {launchUpdateFromVNode} from '../TreeBuilder'; -import {onlyUpdateChildVNodes} from '../vnode/VNodeCreator'; -import {setParentsChildShouldUpdate} from '../vnode/VNodeShouldUpdate'; +import { travelVNodeTree } from '../vnode/VNodeUtils'; +import { launchUpdateFromVNode } from '../TreeBuilder'; +import { onlyUpdateChildVNodes } from '../vnode/VNodeCreator'; +import { setParentsChildShouldUpdate } from '../vnode/VNodeShouldUpdate'; +import { createChildrenByDiff } from '../diff/nodeDiffComparator'; // 从依赖中找到匹配context的VNode function matchDependencies(depContexts, context, vNode): boolean { @@ -56,7 +56,7 @@ function handleContextChange(processing: VNode, context: ContextType): void }, node => // 如果这是匹配的provider,则不要更深入地扫描 node.tag === ContextProvider && node.type === processing.type - , processing); + , processing, null); // 找到了依赖context的子节点,触发一次更新 if (isMatch) { @@ -92,7 +92,7 @@ function captureContextProvider(processing: VNode): VNode | null { } const newElements = newProps.children; - processing.child = createVNodeChildren(processing, newElements); + processing.child = createChildrenByDiff(processing, processing.child, newElements, !processing.isCreated); return processing.child; } diff --git a/libs/horizon/src/renderer/render/DomComponent.ts b/libs/horizon/src/renderer/render/DomComponent.ts index 7aef0d8d..ace8f10f 100644 --- a/libs/horizon/src/renderer/render/DomComponent.ts +++ b/libs/horizon/src/renderer/render/DomComponent.ts @@ -13,9 +13,10 @@ import { isTextChild, } from '../../dom/DOMOperator'; import { FlagUtils } from '../vnode/VNodeFlags'; -import { createVNodeChildren, markRef } from './BaseComponent'; +import { markRef } from './BaseComponent'; import { DomComponent, DomPortal, DomText } from '../vnode/VNodeTags'; import { travelVNodeTree } from '../vnode/VNodeUtils'; +import { createChildrenByDiff } from '../diff/nodeDiffComparator'; function updateDom( processing: VNode, @@ -44,7 +45,7 @@ function updateDom( FlagUtils.markUpdate(processing); } else { // 其它的类型,数据有变化才标记更新 - if (changeList.length) { + if (changeList.size) { FlagUtils.markUpdate(processing); } } @@ -88,7 +89,7 @@ export function bubbleRender(processing: VNode) { }, node => // 已经append到父节点,或者是DomPortal都不需要处理child了 node.tag === DomComponent || node.tag === DomText || node.tag === DomPortal - , processing); + , processing, null); } processing.realNode = dom; @@ -123,7 +124,7 @@ function captureDomComponent(processing: VNode): VNode | null { } markRef(processing); - processing.child = createVNodeChildren(processing, nextChildren); + processing.child = createChildrenByDiff(processing, processing.child, nextChildren, !processing.isCreated); return processing.child; } diff --git a/libs/horizon/src/renderer/render/DomPortal.ts b/libs/horizon/src/renderer/render/DomPortal.ts index e8da4a6e..d3f79e58 100644 --- a/libs/horizon/src/renderer/render/DomPortal.ts +++ b/libs/horizon/src/renderer/render/DomPortal.ts @@ -1,7 +1,6 @@ import type { VNode } from '../Types'; import { resetNamespaceCtx, setNamespaceCtx } from '../ContextSaver'; import { createChildrenByDiff } from '../diff/nodeDiffComparator'; -import { createVNodeChildren } from './BaseComponent'; import { prePortal } from '../../dom/DOMOperator'; export function bubbleRender(processing: VNode) { @@ -17,9 +16,9 @@ function capturePortalComponent(processing: VNode) { const newElements = processing.props; if (processing.isCreated) { - processing.child = createChildrenByDiff(processing, null, newElements); + processing.child = createChildrenByDiff(processing, null, newElements, true); } else { - processing.child = createVNodeChildren(processing, newElements); + processing.child = createChildrenByDiff(processing, processing.child, newElements, !processing.isCreated); } return processing.child; } diff --git a/libs/horizon/src/renderer/render/Fragment.ts b/libs/horizon/src/renderer/render/Fragment.ts index 27c2b5c1..37dc6c93 100644 --- a/libs/horizon/src/renderer/render/Fragment.ts +++ b/libs/horizon/src/renderer/render/Fragment.ts @@ -1,11 +1,11 @@ import type {VNode} from '../Types'; -import {createVNodeChildren} from './BaseComponent'; +import { createChildrenByDiff } from '../diff/nodeDiffComparator'; export function bubbleRender() {} function captureFragment(processing: VNode) { const newElement = processing.props; - processing.child = createVNodeChildren(processing, newElement); + processing.child = createChildrenByDiff(processing, processing.child, newElement, !processing.isCreated); return processing.child; } diff --git a/libs/horizon/src/renderer/render/FunctionComponent.ts b/libs/horizon/src/renderer/render/FunctionComponent.ts index ea975abd..0575257a 100644 --- a/libs/horizon/src/renderer/render/FunctionComponent.ts +++ b/libs/horizon/src/renderer/render/FunctionComponent.ts @@ -4,11 +4,11 @@ import {mergeDefaultProps} from './LazyComponent'; import {getOldContext} from '../components/context/CompatibleContext'; import {resetDepContexts} from '../components/context/Context'; import {exeFunctionHook} from '../hooks/HookMain'; -import {createVNodeChildren} from './BaseComponent'; import {ForwardRef} from '../vnode/VNodeTags'; import {FlagUtils, Update} from '../vnode/VNodeFlags'; import {getContextChangeCtx} from '../ContextSaver'; import {onlyUpdateChildVNodes} from '../vnode/VNodeCreator'; +import { createChildrenByDiff } from '../diff/nodeDiffComparator'; // 在useState, useReducer的时候,会触发state变化 let stateChange = false; @@ -79,7 +79,7 @@ export function captureFunctionComponent( return onlyUpdateChildVNodes(processing); } - processing.child = createVNodeChildren(processing, newElements); + processing.child = createChildrenByDiff(processing, processing.child, newElements, !processing.isCreated); return processing.child; } diff --git a/libs/horizon/src/renderer/render/MemoComponent.ts b/libs/horizon/src/renderer/render/MemoComponent.ts index a0cd75f3..84daa883 100644 --- a/libs/horizon/src/renderer/render/MemoComponent.ts +++ b/libs/horizon/src/renderer/render/MemoComponent.ts @@ -1,7 +1,7 @@ import type {VNode} from '../Types'; import {mergeDefaultProps} from './LazyComponent'; -import {updateVNode, onlyUpdateChildVNodes, updateVNodePath, createFragmentVNode, createUndeterminedVNode} from '../vnode/VNodeCreator'; +import {updateVNode, onlyUpdateChildVNodes, createFragmentVNode, createUndeterminedVNode} from '../vnode/VNodeCreator'; import {shallowCompare} from '../utils/compare'; import { TYPE_FRAGMENT, @@ -29,7 +29,7 @@ export function captureMemoComponent( } newChild.parent = processing; newChild.ref = processing.ref; - updateVNodePath(newChild); + newChild.path = newChild.parent.path + newChild.cIndex; processing.child = newChild; return newChild; @@ -48,7 +48,7 @@ export function captureMemoComponent( const newChild = updateVNode(firstChild, newProps); newChild.parent = processing; newChild.cIndex = 0; - updateVNodePath(newChild); + newChild.path = newChild.parent.path + newChild.cIndex; newChild.ref = processing.ref; processing.child = newChild; diff --git a/libs/horizon/src/renderer/render/SuspenseComponent.ts b/libs/horizon/src/renderer/render/SuspenseComponent.ts index c2d6773b..cdc2f4a4 100644 --- a/libs/horizon/src/renderer/render/SuspenseComponent.ts +++ b/libs/horizon/src/renderer/render/SuspenseComponent.ts @@ -1,7 +1,7 @@ import type {VNode, PromiseType} from '../Types'; import {FlagUtils, Interrupted} from '../vnode/VNodeFlags'; -import {onlyUpdateChildVNodes, updateVNode, updateVNodePath, createFragmentVNode} from '../vnode/VNodeCreator'; +import {onlyUpdateChildVNodes, updateVNode, createFragmentVNode} from '../vnode/VNodeCreator'; import { ClassComponent, IncompleteClassComponent, @@ -44,7 +44,7 @@ function createFallback(processing: VNode, fallbackChildren) { fallbackFragment.parent = processing; fallbackFragment.eIndex = 1; fallbackFragment.cIndex = 1; - updateVNodePath(fallbackFragment); + fallbackFragment.path = fallbackFragment.parent.path + fallbackFragment.cIndex; processing.suspenseChildStatus = SuspenseChildStatus.ShowFallback; return fallbackFragment; @@ -76,7 +76,7 @@ function createSuspenseChildren(processing: VNode, newChildren) { childFragment.parent = processing; childFragment.cIndex = 0; - updateVNodePath(childFragment); + childFragment.path = childFragment.parent.path + childFragment.cIndex; processing.child = childFragment; processing.promiseResolve = false; return processing.child; diff --git a/libs/horizon/src/renderer/render/TreeRoot.ts b/libs/horizon/src/renderer/render/TreeRoot.ts index c9f54646..9b5eaa86 100644 --- a/libs/horizon/src/renderer/render/TreeRoot.ts +++ b/libs/horizon/src/renderer/render/TreeRoot.ts @@ -1,10 +1,10 @@ import type {VNode} from '../Types'; import {throwIfTrue} from '../utils/throwIfTrue'; import {processUpdates} from '../UpdateHandler'; -import {createVNodeChildren} from './BaseComponent'; import {resetNamespaceCtx, setNamespaceCtx} from '../ContextSaver'; import {resetOldCtx} from '../components/context/CompatibleContext'; import {onlyUpdateChildVNodes} from '../vnode/VNodeCreator'; +import { createChildrenByDiff } from '../diff/nodeDiffComparator'; export function bubbleRender(processing: VNode) { resetNamespaceCtx(processing); @@ -33,7 +33,7 @@ function updateTreeRoot(processing) { if (newElement === oldElement) { return onlyUpdateChildVNodes(processing); } - processing.child = createVNodeChildren(processing, newElement); + processing.child = createChildrenByDiff(processing, processing.child, newElement, !processing.isCreated); return processing.child; } diff --git a/libs/horizon/src/renderer/render/class/ClassLifeCycleProcessor.ts b/libs/horizon/src/renderer/render/class/ClassLifeCycleProcessor.ts index 40fbbf40..90f662c3 100644 --- a/libs/horizon/src/renderer/render/class/ClassLifeCycleProcessor.ts +++ b/libs/horizon/src/renderer/render/class/ClassLifeCycleProcessor.ts @@ -18,7 +18,7 @@ export function callDerivedStateFromProps( getDerivedStateFromProps: (props: object, state: object) => object, nextProps: object, ) { - if (typeof getDerivedStateFromProps === 'function') { + if (getDerivedStateFromProps) { const oldState = processing.state; // 调用class组件的getDerivedStateFromProps函数 @@ -57,7 +57,7 @@ export function callShouldComponentUpdate( ) { const inst = processing.realNode; - if (typeof inst.shouldComponentUpdate === 'function') { + if (inst.shouldComponentUpdate) { return inst.shouldComponentUpdate(newProps, newState, newContext); } @@ -91,10 +91,10 @@ export function callConstructor(processing: VNode, ctor: any, props: any): any { export function callComponentWillMount(processing, inst, newProps?) { const oldState = inst.state; - if (typeof inst.componentWillMount === 'function') { + if (inst.componentWillMount) { inst.componentWillMount(); } - if (typeof inst.UNSAFE_componentWillMount === 'function') { + if (inst.UNSAFE_componentWillMount) { inst.UNSAFE_componentWillMount(); } @@ -108,21 +108,21 @@ export function callComponentWillMount(processing, inst, newProps?) { } export function callComponentWillUpdate(inst, newProps, newState, nextContext) { - if (typeof inst.componentWillUpdate === 'function') { + if (inst.componentWillUpdate) { inst.componentWillUpdate(newProps, newState, nextContext); } - if (typeof inst.UNSAFE_componentWillUpdate === 'function') { + if (inst.UNSAFE_componentWillUpdate) { inst.UNSAFE_componentWillUpdate(newProps, newState, nextContext); } } export function callComponentWillReceiveProps(inst, newProps: object, newContext: object) { const oldState = inst.state; - if (typeof inst.componentWillReceiveProps === 'function') { + if (inst.componentWillReceiveProps) { inst.componentWillReceiveProps(newProps, newContext); } - if (typeof inst.UNSAFE_componentWillReceiveProps === 'function') { + if (inst.UNSAFE_componentWillReceiveProps) { inst.UNSAFE_componentWillReceiveProps(newProps, newContext); } if (inst.state !== oldState) { @@ -132,21 +132,21 @@ export function callComponentWillReceiveProps(inst, newProps: object, newContext export function markComponentDidMount(processing: VNode) { const inst = processing.realNode; - if (typeof inst.componentDidMount === 'function') { + if (inst.componentDidMount) { FlagUtils.markUpdate(processing); } } export function markGetSnapshotBeforeUpdate(processing: VNode) { const inst = processing.realNode; - if (typeof inst.getSnapshotBeforeUpdate === 'function') { + if (inst.getSnapshotBeforeUpdate) { FlagUtils.markSnapshot(processing); } } export function markComponentDidUpdate(processing: VNode) { const inst = processing.realNode; - if (typeof inst.componentDidUpdate === 'function') { + if (inst.componentDidUpdate) { FlagUtils.markUpdate(processing); } } diff --git a/libs/horizon/src/renderer/submit/LifeCycleHandler.ts b/libs/horizon/src/renderer/submit/LifeCycleHandler.ts index dd68847b..5d8d649a 100644 --- a/libs/horizon/src/renderer/submit/LifeCycleHandler.ts +++ b/libs/horizon/src/renderer/submit/LifeCycleHandler.ts @@ -17,7 +17,7 @@ import { SuspenseComponent, MemoComponent, } from '../vnode/VNodeTags'; -import { FlagUtils, ResetText, Clear, Update } from '../vnode/VNodeFlags'; +import { FlagUtils, ResetText, Clear, Update, DirectAddition } from '../vnode/VNodeFlags'; import { mergeDefaultProps } from '../render/LazyComponent'; import { submitDomUpdate, @@ -147,7 +147,7 @@ function hideOrUnhideAllChildren(vNode, isHidden) { unHideDom(node.tag, instance, node.props); } } - }); + }, null, vNode, null); } function attachRef(vNode: VNode) { @@ -216,7 +216,7 @@ function unmountNestedVNodes(vNode: VNode): void { }, node => // 如果是DomPortal,不需要遍历child node.tag === DomPortal - ); + , vNode, null); } function submitAddition(vNode: VNode): void { @@ -241,6 +241,11 @@ function submitAddition(vNode: VNode): void { FlagUtils.removeFlag(parent, ResetText); } + if ((vNode.flags & DirectAddition) === DirectAddition) { + insertOrAppendPlacementNode(vNode, null, parentDom); + FlagUtils.removeFlag(vNode, DirectAddition); + return; + } const before = getSiblingDom(vNode); insertOrAppendPlacementNode(vNode, before, parentDom); } @@ -314,7 +319,7 @@ function unmountDomComponents(vNode: VNode): void { } }, node => // 如果是dom不用再遍历child - node.tag === DomComponent || node.tag === DomText, null, (node) => { + node.tag === DomComponent || node.tag === DomText, vNode, (node) => { if (node.tag === DomPortal) { // 当离开portal,需要重新设置parent currentParentIsValid = false; diff --git a/libs/horizon/src/renderer/submit/Submit.ts b/libs/horizon/src/renderer/submit/Submit.ts index ae4027f3..e80f911a 100644 --- a/libs/horizon/src/renderer/submit/Submit.ts +++ b/libs/horizon/src/renderer/submit/Submit.ts @@ -87,7 +87,10 @@ export function submitToRender(treeRoot) { } function beforeSubmit(dirtyNodes: Array) { - dirtyNodes.forEach(node => { + let node; + const nodesLength = dirtyNodes.length; + for(let i = 0; i < nodesLength; i++) { + node = dirtyNodes[i]; try { if ((node.flags & Snapshot) === Snapshot) { callBeforeSubmitLifeCycles(node); @@ -95,35 +98,42 @@ function beforeSubmit(dirtyNodes: Array) { } catch (error) { handleSubmitError(node, error); } - }); + } } function submit(dirtyNodes: Array) { - dirtyNodes.forEach(node => { + let node; + const nodesLength = dirtyNodes.length; + let isAdd; + let isUpdate; + let isDeletion; + let isClear; + for(let i = 0; i < nodesLength; i++) { + node = dirtyNodes[i]; try { if ((node.flags & ResetText) === ResetText) { submitResetTextContent(node); } - + if ((node.flags & Ref) === Ref) { if (!node.isCreated) { // 需要执行 detachRef(node, true); } } - - const isAdd = (node.flags & Addition) === Addition; - const isUpdate = (node.flags & Update) === Update; + + isAdd = (node.flags & Addition) === Addition; + isUpdate = (node.flags & Update) === Update; if (isAdd && isUpdate) { // Addition submitAddition(node); FlagUtils.removeFlag(node, Addition); - + // Update submitUpdate(node); } else { - const isDeletion = (node.flags & Deletion) === Deletion; - const isClear = (node.flags & Clear) === Clear; + isDeletion = (node.flags & Deletion) === Deletion; + isClear = (node.flags & Clear) === Clear; if (isAdd) { submitAddition(node); FlagUtils.removeFlag(node, Addition); @@ -139,23 +149,26 @@ function submit(dirtyNodes: Array) { } catch (error) { handleSubmitError(node, error); } - }); + } } function afterSubmit(dirtyNodes: Array) { - dirtyNodes.forEach(node => { + let node; + const nodesLength = dirtyNodes.length; + for(let i = 0; i < nodesLength; i++) { + node = dirtyNodes[i]; try { if ((node.flags & Update) === Update || (node.flags & Callback) === Callback) { callAfterSubmitLifeCycles(node); } - + if ((node.flags & Ref) === Ref) { attachRef(node); } } catch (error) { handleSubmitError(node, error); } - }); + } } export function setRootThrowError(error: any) { diff --git a/libs/horizon/src/renderer/vnode/VNodeCreator.ts b/libs/horizon/src/renderer/vnode/VNodeCreator.ts index b37fa3c7..35b1b354 100644 --- a/libs/horizon/src/renderer/vnode/VNodeCreator.ts +++ b/libs/horizon/src/renderer/vnode/VNodeCreator.ts @@ -157,10 +157,6 @@ export function createVNode(tag: VNodeTag | string, ...secondArg) { return vNode; } -export function updateVNodePath(vNode: VNode) { - vNode.path = vNode.parent.path + vNode.cIndex; -} - export function createVNodeFromElement(element: JSXElement): VNode { const type = element.type; const key = element.key; @@ -183,7 +179,7 @@ export function onlyUpdateChildVNodes(processing: VNode): VNode | null { let child: VNode | null = processing.child; while (child !== null) { updateVNode(child, child.props); - updateVNodePath(child); + child.path = child.parent.path + child.cIndex; child = child.next; } } diff --git a/libs/horizon/src/renderer/vnode/VNodeFlags.ts b/libs/horizon/src/renderer/vnode/VNodeFlags.ts index 62f98803..af0c2fad 100644 --- a/libs/horizon/src/renderer/vnode/VNodeFlags.ts +++ b/libs/horizon/src/renderer/vnode/VNodeFlags.ts @@ -5,20 +5,21 @@ import type { VNode } from '../Types'; -export const InitFlag = /** */ 0b000000000000; +export const InitFlag = /** */ 0; // vNode节点的flags -export const Addition = /** */ 0b100000000000; -export const Update = /** */ 0b010000000000; -export const Deletion = /** */ 0b001000000000; -export const ResetText =/** */ 0b000100000000; -export const Callback = /** */ 0b000010000000; -export const DidCapture =/** */ 0b000001000000; -export const Ref = /** */ 0b000000100000; -export const Snapshot = /** */ 0b000000010000; -export const Interrupted = /** */ 0b000000001000; // 被中断了,抛出错误的vNode以及它的父vNode -export const ShouldCapture =/** */ 0b000000000100; -export const ForceUpdate = /** */ 0b000000000010; // For suspense -export const Clear = /** */ 0b000000000001; +export const DirectAddition = /** */ 1 << 0; // 在本次更新前入股父dom没有子节点,说明本次可以直接添加至父节点,不需要通过 getSiblingDom 找到 before 节点 +export const Addition = /** */ 1 << 1; +export const Update = /** */ 1 << 2; +export const Deletion = /** */ 1 << 3; +export const ResetText =/** */ 1 << 4; +export const Callback = /** */ 1 << 5; +export const DidCapture =/** */ 1 << 6; +export const Ref = /** */ 1 << 7; +export const Snapshot = /** */ 1 << 8; +export const Interrupted = /** */ 1 << 9; // 被中断了,抛出错误的vNode以及它的父vNode +export const ShouldCapture =/** */ 1 << 11; +export const ForceUpdate = /** */ 1 << 12; // For suspense +export const Clear = /** */ 1 << 13; const LifecycleEffectArr = Update | Callback | Ref | Snapshot; export class FlagUtils { @@ -44,6 +45,10 @@ export class FlagUtils { static setAddition(node: VNode) { node.flags = Addition; } + + static markDirectAddition(node: VNode) { + node.flags |= DirectAddition; + } static markUpdate(node: VNode) { node.flags |= Update; } diff --git a/libs/horizon/src/renderer/vnode/VNodeUtils.ts b/libs/horizon/src/renderer/vnode/VNodeUtils.ts index 400ee792..a6521757 100644 --- a/libs/horizon/src/renderer/vnode/VNodeUtils.ts +++ b/libs/horizon/src/renderer/vnode/VNodeUtils.ts @@ -27,11 +27,11 @@ export function travelChildren(beginVNode: VNode, handleVNode: Function, isFinis export function travelVNodeTree( beginVNode: VNode, handleVNode: Function, - childFilter: Function = () => false, // 返回true不处理child - finishVNode?: VNode, // 结束遍历节点,有时候和beginVNode不相同 - handleWhenToParent?: Function + childFilter: ((node: VNode) => boolean) | null, // 返回true不处理child + finishVNode: VNode, // 结束遍历节点,有时候和beginVNode不相同 + handleWhenToParent: Function | null ): VNode | null { - const overVNode = finishVNode || beginVNode; + const filter = childFilter === null; let node = beginVNode; while (true) { @@ -43,20 +43,20 @@ export function travelVNodeTree( // 找子节点 const childVNode = node.child; - if (childVNode !== null && !childFilter(node)) { + if (childVNode !== null && (filter || !childFilter(node))) { childVNode.parent = node; node = childVNode; continue; } // 回到开始节点 - if (node === overVNode) { + if (node === finishVNode) { return null; } // 找兄弟,没有就往上再找兄弟 while (node.next === null) { - if (node.parent === null || node.parent === overVNode) { + if (node.parent === null || node.parent === finishVNode) { return null; } node = node.parent; @@ -119,7 +119,7 @@ export function findDomVNode(vNode: VNode): VNode | null { return node; } return null; - }); + }, null, vNode, null); } export function findDOMByClassInst(inst) { @@ -169,7 +169,7 @@ export function getSiblingDom(vNode: VNode): Element | null { // 如果不是dom节点,往下找 while (!isDomVNode(node)) { // 如果节点也是Addition - if ((node.flags & Addition) ===Addition) { + if ((node.flags & Addition) === Addition) { continue findSibling; } @@ -183,7 +183,7 @@ export function getSiblingDom(vNode: VNode): Element | null { } } - if ((node.flags & Addition) ===InitFlag) { + if ((node.flags & Addition) === InitFlag) { // 找到 return node.realNode; }