Match-id-6ca59de3cf86b4a09201bae1b847ec3778c100c8

This commit is contained in:
* 2022-01-21 10:13:08 +08:00 committed by *
commit 09831eef5c
15 changed files with 223 additions and 220 deletions

View File

@ -73,6 +73,7 @@ function isInDocument(dom) {
if (dom && dom.ownerDocument) { if (dom && dom.ownerDocument) {
return isNodeContainsByTargetNode(dom.ownerDocument.documentElement, dom); return isNodeContainsByTargetNode(dom.ownerDocument.documentElement, dom);
} }
return false;
} }
// 判断一个标签是否有设置选择范围的能力 // 判断一个标签是否有设置选择范围的能力

View File

@ -34,12 +34,12 @@ export function watchValueChange(dom) {
// currentVal存储最新值并重写value的setter、getter // currentVal存储最新值并重写value的setter、getter
let currentVal = String(dom[keyForValue]); let currentVal = String(dom[keyForValue]);
const setFunc = descriptor.set; const setFunc = descriptor?.set;
Object.defineProperty(dom, keyForValue, { Object.defineProperty(dom, keyForValue, {
...descriptor, ...descriptor,
set: function (value) { set: function(value) {
currentVal = String(value); currentVal = String(value);
setFunc.apply(this, [value]); setFunc?.apply(this, [value]);
}, },
}); });

View File

@ -12,45 +12,6 @@ function getItemKey(item: any, index: number): string {
return '.' + index.toString(36); return '.' + index.toString(36);
} }
function mapChildrenToArray(
children: any,
arr: Array<any>,
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_COMMON_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. '
);
default:
return;
}
}
function processArrayChildren( function processArrayChildren(
children: any, children: any,
arr: Array<any>, arr: Array<any>,
@ -100,6 +61,44 @@ function callMapFun(
} }
} }
function mapChildrenToArray(
children: any,
arr: Array<any>,
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_COMMON_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 // 在 children 里的每个直接子节点上调用一个函数,并将 this 设置为 thisArg
function mapChildren( function mapChildren(
children: any, children: any,
@ -111,9 +110,7 @@ function mapChildren(
} }
let count = 0; let count = 0;
const result = []; const result = [];
mapChildrenToArray(children, result, '', (child) => { mapChildrenToArray(children, result, '', child => func.call(context, child, count++));
return func.call(context, child, count++);
});
return result; return result;
} }

View File

@ -23,12 +23,20 @@ export function JSXElement(type, key, ref, vNode, props) {
// 所属的class组件 // 所属的class组件
belongClassVNode: vNode, belongClassVNode: vNode,
}; };
}; }
function isValidKey(key) { function isValidKey(key) {
return key !== 'key' && key !== 'ref' && key !== '__source'; 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) { function buildElement(isClone, type, setting, ...children) {
// setting中的值优先级最高clone情况下从 type 中取值,创建情况下直接赋值为 null // setting中的值优先级最高clone情况下从 type 中取值,创建情况下直接赋值为 null
const key = (setting && setting.key !== undefined) ? String(setting.key) : (isClone ? type.key : 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); 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) { export function cloneElement(element, setting, ...children) {
return buildElement(true, element, setting, ...children); return buildElement(true, element, setting, ...children);
} }

View File

@ -37,7 +37,7 @@ export function startUpdate(
launchUpdateFromVNode(treeRoot); launchUpdateFromVNode(treeRoot);
} }
export function getFirstCustomDom(treeRoot: VNode): Element | Text | null { export function getFirstCustomDom(treeRoot?: VNode | null): Element | Text | null {
if (treeRoot?.child) { if (treeRoot?.child) {
return treeRoot.child.realNode; return treeRoot.child.realNode;
} }

View File

@ -204,7 +204,7 @@ export function tryRenderRoot(treeRoot: VNode) {
} }
// 发起更新 // 发起更新
export function launchUpdateFromVNode(vNode: VNode): null | void { export function launchUpdateFromVNode(vNode: VNode) {
// 检查循环调用 // 检查循环调用
checkLoopingUpdateLimit(); checkLoopingUpdateLimit();
@ -213,7 +213,7 @@ export function launchUpdateFromVNode(vNode: VNode): null | void {
if (treeRoot === null) { if (treeRoot === null) {
// 可能场景是the componentWillUnmount method 或 useEffect cleanup function 方法中写异步任务并且修改state。 // 可能场景是the componentWillUnmount method 或 useEffect cleanup function 方法中写异步任务并且修改state。
// 因为异步回调的时候root都可能被清除了。 // 因为异步回调的时候root都可能被清除了。
return null; return;
} }
// 保存待刷新的节点 // 保存待刷新的节点

View File

@ -31,9 +31,9 @@ function useEffect(
} }
if (stage === HookStage.Init) { if (stage === HookStage.Init) {
return useEffectForInit(effectFunc, deps, effectType); useEffectForInit(effectFunc, deps, effectType);
} else if (stage === HookStage.Update) { } else if (stage === HookStage.Update) {
return useEffectForUpdate(effectFunc, deps, effectType); useEffectForUpdate(effectFunc, deps, effectType);
} }
} }

View File

@ -15,6 +15,32 @@ import { createChildrenByDiff } from '../diff/nodeDiffComparator';
import {onlyUpdateChildVNodes} from '../vnode/VNodeCreator'; import {onlyUpdateChildVNodes} from '../vnode/VNodeCreator';
import componentRenders from './index'; 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 { export function captureVNode(processing: VNode): VNode | null {
const component = componentRenders[processing.tag]; const component = componentRenders[processing.tag];
@ -38,31 +64,6 @@ export function captureVNode(processing: VNode): VNode | null {
return component.captureRender(processing, shouldUpdate); 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) { export function createVNodeChildren(processing: VNode, nextChildren: any) {
const isComparing = !processing.isCreated; const isComparing = !processing.isCreated;

View File

@ -20,7 +20,7 @@ import {
markComponentDidUpdate, markComponentDidUpdate,
markGetSnapshotBeforeUpdate, markGetSnapshotBeforeUpdate,
} from './class/ClassLifeCycleProcessor'; } from './class/ClassLifeCycleProcessor';
import {FlagUtils} from '../vnode/VNodeFlags'; import { FlagUtils } from '../vnode/VNodeFlags';
import { createVNodeChildren, markRef } from './BaseComponent'; import { createVNodeChildren, markRef } from './BaseComponent';
import { import {
createUpdateArray, createUpdateArray,
@ -30,23 +30,78 @@ import { getContextChangeCtx, setContextChangeCtx } from '../ContextSaver';
import { setProcessingClassVNode } from '../GlobalVar'; import { setProcessingClassVNode } from '../GlobalVar';
import { onlyUpdateChildVNodes } from '../vnode/VNodeCreator'; import { onlyUpdateChildVNodes } from '../vnode/VNodeCreator';
export function captureRender(processing: VNode): VNode | null { // 获取当前节点的context
const clazz = processing.type; export function getCurrentContext(clazz, processing: VNode) {
const props = processing.props; const context = clazz.contextType;
const nextProps = processing.isLazyComponent ? mergeDefaultProps(clazz, props) : props; return typeof context === 'object' && context !== null
return captureClassComponent(processing, clazz, nextProps); ? getNewContext(processing, context)
: getOldContext(processing, clazz, true);
} }
export function bubbleRender(processing: VNode) { // 挂载实例
if (isOldProvider(processing.type)) { function mountInstance(clazz, processing: VNode, nextProps: object) {
resetOldCtx(processing); 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);
} }
} }
// 用于未完成的类组件 function markLifeCycle(processing: VNode, nextProps: object, shouldUpdate: Boolean) {
export function getIncompleteClassComponent(clazz, processing: VNode, nextProps: object):VNode | null { if (processing.isCreated) {
mountInstance(clazz, processing, nextProps); markComponentDidMount(processing);
return createChildren(clazz, processing); } else if (processing.state !== processing.oldState || shouldUpdate) {
markComponentDidUpdate(processing);
markGetSnapshotBeforeUpdate(processing);
}
} }
// 用于类组件 // 用于类组件
@ -127,77 +182,21 @@ export function captureClassComponent(processing: VNode, clazz: any, nextProps:
} }
} }
// 挂载实例 export function captureRender(processing: VNode): VNode | null {
function mountInstance(clazz, processing: VNode, nextProps: object) { const clazz = processing.type;
if (!processing.isCreated) { const props = processing.props;
processing.isCreated = true; const nextProps = processing.isLazyComponent ? mergeDefaultProps(clazz, props) : props;
FlagUtils.markAddition(processing); return captureClassComponent(processing, clazz, nextProps);
}
// 构造实例
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 bubbleRender(processing: VNode) {
function createChildren(clazz: any, processing: VNode) { if (isOldProvider(processing.type)) {
markRef(processing); resetOldCtx(processing);
setProcessingClassVNode(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);
} }
} }
function markLifeCycle(processing: VNode, nextProps: object, shouldUpdate: Boolean) { // 用于未完成的类组件
if (processing.isCreated) { export function getIncompleteClassComponent(clazz, processing: VNode, nextProps: object): VNode | null {
markComponentDidMount(processing); mountInstance(clazz, processing, nextProps);
} else if (processing.state !== processing.oldState || shouldUpdate) { return createChildren(clazz, processing);
markComponentDidUpdate(processing);
markGetSnapshotBeforeUpdate(processing);
}
} }

View File

@ -7,14 +7,8 @@ import {FlagUtils} from '../vnode/VNodeFlags';
import {exeFunctionHook} from '../hooks/HookMain'; import {exeFunctionHook} from '../hooks/HookMain';
import {createVNodeChildren} from './BaseComponent'; import {createVNodeChildren} from './BaseComponent';
export function captureRender(processing: VNode): VNode | null {
return captureIndeterminateComponent(processing);
}
export function bubbleRender() {}
function captureIndeterminateComponent( function captureIndeterminateComponent(
processing: VNode | null, processing: VNode,
): VNode | null { ): VNode | null {
const funcComp = processing.type; const funcComp = processing.type;
@ -34,3 +28,9 @@ function captureIndeterminateComponent(
processing.child = createVNodeChildren(processing, newElements); processing.child = createVNodeChildren(processing, newElements);
return processing.child; return processing.child;
} }
export function captureRender(processing: VNode): VNode | null {
return captureIndeterminateComponent(processing);
}
export function bubbleRender() {}

View File

@ -3,12 +3,6 @@ import type {VNode, ContextType} from '../Types';
import {resetDepContexts, getNewContext} from '../components/context/Context'; import {resetDepContexts, getNewContext} from '../components/context/Context';
import {createVNodeChildren} from './BaseComponent'; import {createVNodeChildren} from './BaseComponent';
export function captureRender(processing: VNode): VNode | null {
return captureContextConsumer(processing);
}
export function bubbleRender() {}
function captureContextConsumer(processing: VNode) { function captureContextConsumer(processing: VNode) {
const context: ContextType<any> = processing.type; const context: ContextType<any> = processing.type;
const props = processing.props; const props = processing.props;
@ -21,3 +15,10 @@ function captureContextConsumer(processing: VNode) {
processing.child = createVNodeChildren(processing, newChildren); processing.child = createVNodeChildren(processing, newChildren);
return processing.child; return processing.child;
} }
export function captureRender(processing: VNode): VNode | null {
return captureContextConsumer(processing);
}
export function bubbleRender() {}

View File

@ -14,12 +14,30 @@ import {launchUpdateFromVNode} from '../TreeBuilder';
import {onlyUpdateChildVNodes} from '../vnode/VNodeCreator'; import {onlyUpdateChildVNodes} from '../vnode/VNodeCreator';
import {setParentsChildShouldUpdate} from '../vnode/VNodeShouldUpdate'; import {setParentsChildShouldUpdate} from '../vnode/VNodeShouldUpdate';
export function captureRender(processing: VNode): VNode | null { // 从当前子节点开始向下遍历找到消费此context的组件并更新
return captureContextProvider(processing); function handleContextChange(processing: VNode, context: ContextType<any>): void {
} const vNode = processing.child;
if (vNode === null) {
return;
}
export function bubbleRender(processing: VNode) { let isMatch = false;
resetContextCtx(processing);
// 从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 { function captureContextProvider(processing: VNode): VNode | null {
@ -54,6 +72,14 @@ function captureContextProvider(processing: VNode): VNode | null {
return processing.child; return processing.child;
} }
export function captureRender(processing: VNode): VNode | null {
return captureContextProvider(processing);
}
export function bubbleRender(processing: VNode) {
resetContextCtx(processing);
}
// 从依赖中找到匹配context的VNode // 从依赖中找到匹配context的VNode
function matchDependencies(depContexts, context, vNode): boolean { function matchDependencies(depContexts, context, vNode): boolean {
for (let i = 0; i < depContexts.length; i++) { for (let i = 0; i < depContexts.length; i++) {
@ -77,29 +103,3 @@ function matchDependencies(depContexts, context, vNode): boolean {
return false; return false;
} }
// 从当前子节点开始向下遍历找到消费此context的组件并更新
function handleContextChange(processing: VNode, context: ContextType<any>): 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);
}
}

View File

@ -1,23 +1,23 @@
import type {VNode} from '../Types'; import type { VNode } from '../Types';
import {FlagUtils} from '../vnode/VNodeFlags'; import { FlagUtils } from '../vnode/VNodeFlags';
import {getLazyVNodeTag} from '../vnode/VNodeCreator'; import { getLazyVNodeTag } from '../vnode/VNodeCreator';
import { import {
ClassComponent, ClassComponent,
ForwardRef, ForwardRef,
FunctionComponent, FunctionComponent,
MemoComponent, MemoComponent,
} from '../vnode/VNodeTags'; } from '../vnode/VNodeTags';
import {throwIfTrue} from '../utils/throwIfTrue'; import { throwIfTrue } from '../utils/throwIfTrue';
import {captureFunctionComponent} from './FunctionComponent'; import { captureFunctionComponent } from './FunctionComponent';
import {captureClassComponent} from './ClassComponent'; import { captureClassComponent } from './ClassComponent';
import {captureMemoComponent} from './MemoComponent'; import { captureMemoComponent } from './MemoComponent';
export function captureRender(processing: VNode, shouldUpdate: boolean): VNode | null { export function captureRender(processing: VNode, shouldUpdate: boolean): VNode | null {
return captureLazyComponent(processing, processing.type, shouldUpdate); return captureLazyComponent(processing, processing.type, shouldUpdate);
} }
export function bubbleRender() {} export function bubbleRender() { }
const LazyRendererMap = { const LazyRendererMap = {
[FunctionComponent]: captureFunctionComponent, [FunctionComponent]: captureFunctionComponent,
@ -64,12 +64,13 @@ function captureLazyComponent(
Component, Component,
'', '',
); );
return null;
} }
} }
export function mergeDefaultProps(Component: any, props: object): object { export function mergeDefaultProps(Component: any, props: object): object {
if (Component && Component.defaultProps) { if (Component && Component.defaultProps) {
const clonedProps = {...props}; const clonedProps = { ...props };
const defaultProps = Component.defaultProps; const defaultProps = Component.defaultProps;
Object.keys(defaultProps).forEach(key => { Object.keys(defaultProps).forEach(key => {
if (clonedProps[key] === undefined) { if (clonedProps[key] === undefined) {

View File

@ -70,8 +70,9 @@ function callBeforeSubmitLifeCycles(
case TreeRoot: { case TreeRoot: {
const root = vNode.realNode; const root = vNode.realNode;
clearContainer(root.outerDom); clearContainer(root.outerDom);
return;
} }
// No Default
} }
} }
@ -136,8 +137,9 @@ function callAfterSubmitLifeCycles(
vNode.realNode.focus(); vNode.realNode.focus();
} }
} }
return;
} }
// No Default
} }
} }

View File

@ -142,6 +142,7 @@ export function findDomVNode(vNode: VNode): VNode | null {
if (node.tag === DomComponent || node.tag === DomText) { if (node.tag === DomComponent || node.tag === DomText) {
return node; return node;
} }
return null;
}); });
} }