Match-id-ccf73f6b103072c2d118e5e70aebea0a2f59c065
This commit is contained in:
commit
c2f173dd60
|
@ -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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue