Match-id-ccf73f6b103072c2d118e5e70aebea0a2f59c065

This commit is contained in:
* 2021-12-22 16:47:50 +08:00 committed by *
commit c2f173dd60
1 changed files with 191 additions and 0 deletions

View File

@ -0,0 +1,191 @@
import type { VNodeTag } from './VNodeTags';
import { FlagUtils } from './VNodeFlags';
import {
ClassComponent,
ContextConsumer,
ContextProvider,
ForwardRef,
Fragment,
FunctionComponent,
DomComponent,
DomPortal,
TreeRoot,
DomText,
ClsOrFunComponent,
LazyComponent,
MemoComponent,
SuspenseComponent,
} from './VNodeTags';
import { createUpdateArray } from '../UpdateHandler';
import {
TYPE_CONTEXT,
TYPE_FORWARD_REF, TYPE_FRAGMENT,
TYPE_LAZY,
TYPE_MEMO, TYPE_PROFILER,
TYPE_PROVIDER, TYPE_STRICT_MODE,
TYPE_SUSPENSE,
} from '../utils/elementType';
import { VNode } from './VNode';
import {HorizonElement} from '../Types';
const typeLazyMap = {
[TYPE_FORWARD_REF]: ForwardRef,
[TYPE_MEMO]: MemoComponent,
};
const typeMap = {
...typeLazyMap,
[TYPE_PROVIDER]: ContextProvider,
[TYPE_CONTEXT]: ContextConsumer,
[TYPE_LAZY]: LazyComponent,
};
const newVirtualNode = function(tag: VNodeTag, key?: null | string, vNodeProps?: any, outerDom?: any): VNode {
return new VNode(tag, vNodeProps, key, outerDom);
};
function isClassComponent(comp: Function) {
// 如果使用 getPrototypeOf 方法获取构造函数,不能兼容业务组组件继承组件的使用方式,会误认为是函数组件
// 如果使用静态属性,部分函数高阶组件会将类组件的静态属性复制到自身,导致误判为类组件
// 既然已经兼容使用了该标识符,那么继续使用
return comp.prototype?.isReactComponent === true;
}
// 解析懒组件的tag
export function getLazyVNodeTag(lazyComp: any): string {
let vNodeTag = ClsOrFunComponent;
if (typeof lazyComp === 'function') {
vNodeTag = isClassComponent(lazyComp) ? ClassComponent : FunctionComponent;
} else if (lazyComp !== undefined && lazyComp !== null && typeLazyMap[lazyComp.vtype]) {
vNodeTag = typeLazyMap[lazyComp.vtype];
}
return vNodeTag;
}
// 创建processing
export function updateVNode(vNode: VNode, vNodeProps?: any): VNode {
if (vNode.tag === ClassComponent) {
vNode.oldState = vNode.state;
}
if (vNode.tag === SuspenseComponent) {
vNode.oldSuspenseChildStatus = vNode.suspenseChildStatus;
vNode.oldChildren = vNode.children;
}
vNode.oldProps = vNode.props;
vNode.props = vNodeProps;
vNode.oldRef = vNode.ref;
FlagUtils.setNoFlags(vNode);
vNode.dirtyNodes = [];
vNode.isCreated = false;
return vNode;
}
function getVNodeTag(type: any) {
let vNodeTag = ClsOrFunComponent;
let isLazy = false;
if (typeof type === 'function') {
if (isClassComponent(type)) {
vNodeTag = ClassComponent;
}
} else if (typeof type === 'string') {
vNodeTag = DomComponent;
} else if (type === TYPE_SUSPENSE) {
vNodeTag = SuspenseComponent;
} else if (typeof type === '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}`);
}
return { vNodeTag, isLazy };
}
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]);
vNode.path.push(0);
createUpdateArray(vNode);
break;
}
return vNode;
}
export function updateVNodePath(vNode: VNode) {
vNode.path = [...vNode.parent.path, vNode.cIndex];
}
export function createVNodeFromElement(element: HorizonElement): VNode {
const type = element.type;
const key = element.key;
const props = element.props;
if (type === TYPE_STRICT_MODE || type === TYPE_FRAGMENT || type === TYPE_PROFILER) {
return createVNode(Fragment, key, props.children);
} else {
return createVNode('props', type, key, props);
}
}
// 直接更新子节点属性即可不需要diff
export function onlyUpdateChildVNodes(processing: VNode): Array<VNode> | null {
// 检查子树是否需要更新
if (processing.childShouldUpdate) {
// 此vNode无需更新但是子树需要
if (!processing.isCreated && processing.children && processing.children.length) {
// 更新子节点
processing.children.forEach(child => {
updateVNode(child, child.props);
updateVNodePath(child);
});
}
// 返回子节点,继续遍历
return processing.children;
}
// 子树无需工作
return null;
}