diff --git a/libs/horizon/src/dom/DOMExternal.ts b/libs/horizon/src/dom/DOMExternal.ts index e9404cb7..077d0801 100644 --- a/libs/horizon/src/dom/DOMExternal.ts +++ b/libs/horizon/src/dom/DOMExternal.ts @@ -1,13 +1,13 @@ import { - asyncUpdates, createVNode, getFirstCustomDom, + asyncUpdates, getFirstCustomDom, syncUpdates, startUpdate, + createTreeRootVNode, } from '../renderer/Renderer'; import {createPortal} from '../renderer/components/CreatePortal'; import type {Container} from './DOMOperator'; import {isElement} from './utils/Common'; import {listenDelegatedEvents} from '../event/EventBinding'; import {findDOMByClassInst} from '../renderer/vnode/VNodeUtils'; -import {TreeRoot} from '../renderer/vnode/VNodeTags'; import {Callback} from '../renderer/UpdateHandler'; function createRoot(children: any, container: Container, callback?: Callback) { @@ -19,7 +19,7 @@ function createRoot(children: any, container: Container, callback?: Callback) { } // 调度器创建根节点,并给容器dom赋vNode结构体 - const treeRoot = createVNode(TreeRoot, container); + const treeRoot = createTreeRootVNode(container); container._treeRoot = treeRoot; // 根节点挂接全量事件 diff --git a/libs/horizon/src/renderer/Renderer.ts b/libs/horizon/src/renderer/Renderer.ts index d5cf89da..8928805a 100644 --- a/libs/horizon/src/renderer/Renderer.ts +++ b/libs/horizon/src/renderer/Renderer.ts @@ -9,9 +9,9 @@ import { } from './TreeBuilder'; import { runAsyncEffects } from './submit/HookEffectHandler'; import { Callback, newUpdate, pushUpdate } from './UpdateHandler'; -import { getFirstChild } from './vnode/VNodeUtils'; -export { createVNode } from './vnode/VNodeCreator'; + +export { createVNode, createTreeRootVNode } from './vnode/VNodeCreator'; export { createPortal } from './components/CreatePortal'; export { asyncUpdates, diff --git a/libs/horizon/src/renderer/diff/nodeDiffComparator.ts b/libs/horizon/src/renderer/diff/nodeDiffComparator.ts index 09624161..797687b5 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, createVNode, createVNodeFromElement, updateVNodePath} from '../vnode/VNodeCreator'; +import {updateVNode, createVNodeFromElement, updateVNodePath, createFragmentVNode, createPortalVNode, createDomTextVNode} from '../vnode/VNodeCreator'; import { isSameType, getIteratorFn, @@ -113,7 +113,7 @@ function getNewNode(parentNode: VNode, newChild: any, oldNode: VNode | null) { switch (newNodeType) { case DiffCategory.TEXT_NODE: { if (oldNode === null || oldNode.tag !== DomText) { - resultNode = createVNode(DomText, String(newChild)); + resultNode = createDomTextVNode(String(newChild)); } else { resultNode = updateVNode(oldNode, String(newChild)); } @@ -121,7 +121,7 @@ function getNewNode(parentNode: VNode, newChild: any, oldNode: VNode | null) { } case DiffCategory.ARR_NODE: { if (oldNode === null || oldNode.tag !== Fragment) { - resultNode = createVNode(Fragment, null, newChild); + resultNode = createFragmentVNode(null, newChild); } else { resultNode = updateVNode(oldNode, newChild); } @@ -132,7 +132,7 @@ function getNewNode(parentNode: VNode, newChild: any, oldNode: VNode | null) { if (newChild.type === TYPE_FRAGMENT) { if (oldNode === null || oldNode.tag !== Fragment) { const key = oldNode !== null ? oldNode.key : newChild.key; - resultNode = createVNode(Fragment, key, newChild.props.children); + resultNode = createFragmentVNode(key, newChild.props.children); } else { resultNode = updateVNode(oldNode, newChild); } @@ -151,7 +151,7 @@ function getNewNode(parentNode: VNode, newChild: any, oldNode: VNode | null) { break; } else if (newChild.vtype === TYPE_PORTAL) { if (oldNode === null || oldNode.tag !== DomPortal || oldNode.outerDom !== newChild.outerDom) { - resultNode = createVNode(DomPortal, newChild); + resultNode = createPortalVNode(newChild); } else { resultNode = updateVNode(oldNode, newChild.children || []); } @@ -504,7 +504,7 @@ function diffStringNodeHandler( deleteVNodes(parentNode, firstChildVNode.next); newTextNode.next = null; } else { - newTextNode = createVNode(DomText, String(newChild)); + newTextNode = createDomTextVNode(String(newChild)); deleteVNodes(parentNode, firstChildVNode); } @@ -562,7 +562,7 @@ function diffObjectNodeHandler( if (resultNode === null) { // 新建 if (newChild.type === TYPE_FRAGMENT) { - resultNode = createVNode(Fragment, newChild.key, newChild.props.children); + resultNode = createFragmentVNode(newChild.key, newChild.props.children); } else { resultNode = createVNodeFromElement(newChild); resultNode.ref = newChild.ref; @@ -580,7 +580,7 @@ function diffObjectNodeHandler( } if (resultNode === null) { // 新建 - resultNode = createVNode(DomPortal, newChild); + resultNode = createPortalVNode(newChild); } } diff --git a/libs/horizon/src/renderer/render/MemoComponent.ts b/libs/horizon/src/renderer/render/MemoComponent.ts index d4a10d22..a0cd75f3 100644 --- a/libs/horizon/src/renderer/render/MemoComponent.ts +++ b/libs/horizon/src/renderer/render/MemoComponent.ts @@ -1,14 +1,13 @@ import type {VNode} from '../Types'; import {mergeDefaultProps} from './LazyComponent'; -import {updateVNode, createVNode, onlyUpdateChildVNodes, updateVNodePath} from '../vnode/VNodeCreator'; +import {updateVNode, onlyUpdateChildVNodes, updateVNodePath, createFragmentVNode, createUndeterminedVNode} from '../vnode/VNodeCreator'; import {shallowCompare} from '../utils/compare'; import { TYPE_FRAGMENT, TYPE_PROFILER, TYPE_STRICT_MODE, } from '../../external/JSXElementType'; -import {Fragment} from '../vnode/VNodeTags'; export function bubbleRender() {} @@ -24,9 +23,9 @@ export function captureMemoComponent( let newChild = null; const type = Component.type; if (type === TYPE_STRICT_MODE || type === TYPE_FRAGMENT || type === TYPE_PROFILER) { - newChild = createVNode(Fragment, null, newProps.children); + newChild = createFragmentVNode(null, newProps.children); } else { - newChild = createVNode('props', type, null, newProps, processing); + newChild = createUndeterminedVNode(type, null, newProps); } newChild.parent = processing; newChild.ref = processing.ref; diff --git a/libs/horizon/src/renderer/render/SuspenseComponent.ts b/libs/horizon/src/renderer/render/SuspenseComponent.ts index b601a551..c2d6773b 100644 --- a/libs/horizon/src/renderer/render/SuspenseComponent.ts +++ b/libs/horizon/src/renderer/render/SuspenseComponent.ts @@ -1,12 +1,11 @@ import type {VNode, PromiseType} from '../Types'; import {FlagUtils, Interrupted} from '../vnode/VNodeFlags'; -import {createVNode, onlyUpdateChildVNodes, updateVNode, updateVNodePath} from '../vnode/VNodeCreator'; +import {onlyUpdateChildVNodes, updateVNode, updateVNodePath, createFragmentVNode} from '../vnode/VNodeCreator'; import { ClassComponent, IncompleteClassComponent, SuspenseComponent, - Fragment, } from '../vnode/VNodeTags'; import {pushForceUpdate} from '../UpdateHandler'; import {launchUpdateFromVNode, tryRenderFromRoot} from '../TreeBuilder'; @@ -31,12 +30,12 @@ function createFallback(processing: VNode, fallbackChildren) { if (oldFallbackFragment !== null) { fallbackFragment = updateVNode(oldFallbackFragment, fallbackChildren); } else { - fallbackFragment = createVNode(Fragment, null, fallbackChildren); + fallbackFragment = createFragmentVNode(null, fallbackChildren); FlagUtils.markAddition(fallbackFragment); } } else { // 创建 - fallbackFragment = createVNode(Fragment, null, fallbackChildren); + fallbackFragment = createFragmentVNode(null, fallbackChildren); } processing.child = childFragment; @@ -72,7 +71,7 @@ function createSuspenseChildren(processing: VNode, newChildren) { // SuspenseComponent 中使用 processing.suspenseChildStatus = SuspenseChildStatus.ShowChild; } else { - childFragment = createVNode(Fragment, null, newChildren); + childFragment = createFragmentVNode(null, newChildren); } childFragment.parent = processing; diff --git a/libs/horizon/src/renderer/vnode/VNodeCreator.ts b/libs/horizon/src/renderer/vnode/VNodeCreator.ts index 5feb31f4..11abe1b1 100644 --- a/libs/horizon/src/renderer/vnode/VNodeCreator.ts +++ b/libs/horizon/src/renderer/vnode/VNodeCreator.ts @@ -87,59 +87,71 @@ export function updateVNode(vNode: VNode, vNodeProps?: any): VNode { function getVNodeTag(type: any) { let vNodeTag = ClsOrFunComponent; let isLazy = false; + const componentType = typeof type; - if (typeof type === 'function') { + if (componentType === 'function') { if (isClassComponent(type)) { vNodeTag = ClassComponent; } - } else if (typeof type === 'string') { + } else if (componentType === 'string') { vNodeTag = DomComponent; } else if (type === TYPE_SUSPENSE) { vNodeTag = SuspenseComponent; - } else if (typeof type === 'object' && type !== null && typeMap[type.vtype]) { + } else if (componentType === 'object' && type !== null && typeMap[type.vtype]) { vNodeTag = typeMap[type.vtype]; isLazy = type.vtype === TYPE_LAZY; } else { - throw Error(`Component type is invalid, got: ${type == null ? type : typeof type}`); + throw Error(`Component type is invalid, got: ${type == null ? type : componentType}`); } return { vNodeTag, isLazy }; } +export function createFragmentVNode(fragmentKey, fragmentProps) { + const vNode = newVirtualNode(Fragment, fragmentKey, fragmentProps); + vNode.shouldUpdate = true; + return vNode; +} + +export function createDomTextVNode(content) { + const vNode = newVirtualNode(DomText, null, content); + vNode.shouldUpdate = true; + return vNode; +} + +export function createPortalVNode(portal) { + const children = portal.children ?? []; + const vNode = newVirtualNode(DomPortal, portal.key, children); + vNode.shouldUpdate = true; + vNode.outerDom = portal.outerDom; + return vNode; +} + +export function createUndeterminedVNode(type, key, props) { + const { vNodeTag, isLazy } = getVNodeTag(type); + + const vNode = newVirtualNode(vNodeTag, key, props); + vNode.type = type; + vNode.shouldUpdate = true; + + // lazy类型的特殊处理 + vNode.isLazyComponent = isLazy; + if (isLazy) { + vNode.lazyType = type; + } + return vNode; +} + +export function createTreeRootVNode(container) { + const vNode = newVirtualNode(TreeRoot, null, null, container); + vNode.path.push(0); + createUpdateArray(vNode); + return vNode; +} + +// TODO: 暂时保留给测试用例使用,后续修改测试用例 export function createVNode(tag: VNodeTag | string, ...secondArg) { let vNode = null; switch (tag) { - case Fragment: - const [fragmentKey, fragmentProps] = secondArg; - vNode = newVirtualNode(Fragment, fragmentKey, fragmentProps); - vNode.shouldUpdate = true; - break; - case DomText: - const content = secondArg[0]; - vNode = newVirtualNode(DomText, null, content); - vNode.shouldUpdate = true; - break; - case DomPortal: - const portal = secondArg[0]; - const children = portal.children ?? []; - vNode = newVirtualNode(DomPortal, portal.key, children); - vNode.shouldUpdate = true; - vNode.outerDom = portal.outerDom; - break; - case 'props': - const [type, key, props] = secondArg; - - const { vNodeTag, isLazy } = getVNodeTag(type); - - vNode = newVirtualNode(vNodeTag, key, props); - vNode.type = type; - vNode.shouldUpdate = true; - - // lazy类型的特殊处理 - vNode.isLazyComponent = isLazy; - if (isLazy) { - vNode.lazyType = type; - } - break; case TreeRoot: // 创建treeRoot vNode = newVirtualNode(TreeRoot, null, null, secondArg[0]); @@ -162,9 +174,9 @@ export function createVNodeFromElement(element: JSXElement): VNode { const props = element.props; if (type === TYPE_STRICT_MODE || type === TYPE_FRAGMENT || type === TYPE_PROFILER) { - return createVNode(Fragment, key, props.children); + return createFragmentVNode(key, props.children); } else { - return createVNode('props', type, key, props); + return createUndeterminedVNode(type, key, props); } }