Match-id-380f75464e0bb10e9f8ea83e11081332842887f4
This commit is contained in:
parent
25c3a84991
commit
66ca6c968a
|
@ -69,6 +69,16 @@ function resetProcessingVariables(startUpdateVNode: VNode) {
|
|||
unrecoverableErrorDuringBuild = null;
|
||||
}
|
||||
|
||||
// 收集有变化的节点,在submit阶段继续处理
|
||||
function collectDirtyNodes(vNode: VNode, parent: VNode): void {
|
||||
// 将子树和此vNode的所有效果附加到父树的效果列表中,子项的完成顺序会影响副作用顺序。
|
||||
parent.dirtyNodes.push(...vNode.dirtyNodes);
|
||||
|
||||
if (FlagUtils.hasAnyFlag(vNode)) {
|
||||
parent.dirtyNodes.push(vNode);
|
||||
}
|
||||
}
|
||||
|
||||
// ============================== 向上递归 ==============================
|
||||
|
||||
// 尝试完成当前工作单元,然后移动到下一个兄弟工作单元。如果没有更多的同级,请返回父vNode。
|
||||
|
@ -134,6 +144,51 @@ function handleError(root, error): void {
|
|||
bubbleVNode(processing);
|
||||
}
|
||||
|
||||
// 从多个更新节点中,计算出开始节点。即:找到最近的共同的父辈节点
|
||||
export function calcStartUpdateVNode(treeRoot: VNode) {
|
||||
const toUpdateNodes = Array.from(treeRoot.toUpdateNodes);
|
||||
|
||||
if (toUpdateNodes.length === 0) {
|
||||
return treeRoot;
|
||||
}
|
||||
|
||||
if (toUpdateNodes.length === 1) {
|
||||
return toUpdateNodes[0];
|
||||
}
|
||||
|
||||
// 要计算的节点过多,直接返回根节点
|
||||
if (toUpdateNodes.length > 100) {
|
||||
return treeRoot;
|
||||
}
|
||||
|
||||
// 找到路径最短的长度
|
||||
let minPath = toUpdateNodes[0].path.length;
|
||||
for (let i = 1; i < toUpdateNodes.length; i++) {
|
||||
let pathLen = toUpdateNodes[i].path.length;
|
||||
if (pathLen < minPath) {
|
||||
minPath = pathLen;
|
||||
}
|
||||
}
|
||||
|
||||
// 找出开始不相等的idx
|
||||
let idx = 0;
|
||||
for (; idx < minPath; idx++) {
|
||||
if (!isEqualByIndex(idx, toUpdateNodes)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
// 得到相等的路径
|
||||
let startNodePath = toUpdateNodes[0].path.slice(0, idx);
|
||||
|
||||
let node = treeRoot;
|
||||
for (let i = 1; i < startNodePath.length; i++) {
|
||||
let pathIndex = startNodePath[i];
|
||||
node = getChildByIndex(node, pathIndex);
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
// ============================== 深度遍历 ==============================
|
||||
function buildVNodeTree(treeRoot: VNode) {
|
||||
const preMode = copyExecuteMode();
|
||||
|
@ -271,67 +326,12 @@ function getChildByIndex(vNode: VNode, idx: number) {
|
|||
return node;
|
||||
}
|
||||
|
||||
// 从多个更新节点中,计算出开始节点。即:找到最近的共同的父辈节点
|
||||
export function calcStartUpdateVNode(treeRoot: VNode) {
|
||||
const toUpdateNodes = Array.from(treeRoot.toUpdateNodes);
|
||||
|
||||
if (toUpdateNodes.length === 0) {
|
||||
return treeRoot;
|
||||
}
|
||||
|
||||
if (toUpdateNodes.length === 1) {
|
||||
return toUpdateNodes[0];
|
||||
}
|
||||
|
||||
// 要计算的节点过多,直接返回根节点
|
||||
if (toUpdateNodes.length > 100) {
|
||||
return treeRoot;
|
||||
}
|
||||
|
||||
// 找到路径最短的长度
|
||||
let minPath = toUpdateNodes[0].path.length;
|
||||
for (let i = 1; i < toUpdateNodes.length; i++) {
|
||||
let pathLen = toUpdateNodes[i].path.length;
|
||||
if (pathLen < minPath) {
|
||||
minPath = pathLen;
|
||||
}
|
||||
}
|
||||
|
||||
// 找出开始不相等的idx
|
||||
let idx = 0;
|
||||
for (; idx < minPath; idx++) {
|
||||
if (!isEqualByIndex(idx, toUpdateNodes)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
// 得到相等的路径
|
||||
let startNodePath = toUpdateNodes[0].path.slice(0, idx);
|
||||
|
||||
let node = treeRoot;
|
||||
for (let i = 1; i < startNodePath.length; i++) {
|
||||
let pathIndex = startNodePath[i];
|
||||
node = getChildByIndex(node, pathIndex);
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
export function setBuildResultError() {
|
||||
if (getBuildResult() !== BuildCompleted) {
|
||||
setBuildResult(BuildErrored);
|
||||
}
|
||||
}
|
||||
|
||||
// 收集有变化的节点,在submit阶段继续处理
|
||||
function collectDirtyNodes(vNode: VNode, parent: VNode): void {
|
||||
// 将子树和此vNode的所有效果附加到父树的效果列表中,子项的完成顺序会影响副作用顺序。
|
||||
parent.dirtyNodes.push(...vNode.dirtyNodes);
|
||||
|
||||
if (FlagUtils.hasAnyFlag(vNode)) {
|
||||
parent.dirtyNodes.push(vNode);
|
||||
}
|
||||
}
|
||||
|
||||
// ============================== HorizonDOM使用 ==============================
|
||||
export function runDiscreteUpdates() {
|
||||
if (checkMode(ByAsync) || checkMode(InRender)) {
|
||||
|
|
|
@ -5,24 +5,24 @@ type Trigger<A> = (A) => void;
|
|||
export type UseStateHookType = {
|
||||
useState<S>(
|
||||
initialState: (() => S) | S
|
||||
): [S, Trigger<((S) => S) | S>]
|
||||
): [S, Trigger<((S) => S) | S>];
|
||||
};
|
||||
export type UseReducerHookType = {
|
||||
useReducer<S, P, A>(
|
||||
reducer: (S, A) => S,
|
||||
initArg: P, init?: (P) => S,
|
||||
): [S, Trigger<A>]
|
||||
): [S, Trigger<A>];
|
||||
};
|
||||
export type UseContextHookType = { useContext<T>(context: ContextType<T>,): T };
|
||||
|
||||
export type HorizonElement = {
|
||||
vtype: any,
|
||||
type: any,
|
||||
key: any,
|
||||
ref: any,
|
||||
props: any,
|
||||
vtype: any;
|
||||
type: any;
|
||||
key: any;
|
||||
ref: any;
|
||||
props: any;
|
||||
|
||||
_vNode: any,
|
||||
_vNode: any;
|
||||
};
|
||||
|
||||
export type ProviderType<T> = {
|
||||
|
|
|
@ -4,11 +4,11 @@ import type {PortalType} from '../Types';
|
|||
export function createPortal(
|
||||
children: any,
|
||||
outerDom: any,
|
||||
key: string = null,
|
||||
key: string = '',
|
||||
): PortalType {
|
||||
return {
|
||||
vtype: TYPE_PORTAL,
|
||||
key: key == null ? null : '' + key,
|
||||
key: key == '' ? '' : '' + key,
|
||||
children,
|
||||
outerDom,
|
||||
};
|
||||
|
|
|
@ -10,14 +10,14 @@ enum LayStatus {
|
|||
}
|
||||
|
||||
type LazyContent<T> = {
|
||||
_status: string,
|
||||
_value: () => PromiseType<{default: T}> | PromiseType<T> | T | any
|
||||
_status: string;
|
||||
_value: () => PromiseType<{default: T}> | PromiseType<T> | T | any;
|
||||
};
|
||||
|
||||
export type LazyComponent<T, P> = {
|
||||
vtype: number,
|
||||
_content: P,
|
||||
_load: (content: P) => T,
|
||||
vtype: number;
|
||||
_content: P;
|
||||
_load: (content: P) => T;
|
||||
};
|
||||
|
||||
// lazyContent随着阶段改变,_value改变:
|
||||
|
|
|
@ -51,7 +51,7 @@ export function getOldContext(processing: VNode, clazz: Function, ifProvider: bo
|
|||
|
||||
// 当组件既是提供者,也是消费者时,取上一个context,不能直接取最新context,因为已经被更新为当前组件的context;
|
||||
// 当组件只是消费者时,则取最新context
|
||||
const parentContext = ((ifProvider && isOldProvider(clazz))) ?
|
||||
const parentContext = (ifProvider && isOldProvider(clazz)) ?
|
||||
getOldPreviousContextCtx() :
|
||||
getOldContextCtx();
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@ export enum HookStage {
|
|||
Update = 2,
|
||||
}
|
||||
|
||||
let hookStage: HookStage = null;
|
||||
let hookStage: HookStage | null = null;
|
||||
|
||||
export function getHookStage() {
|
||||
return hookStage;
|
||||
|
|
|
@ -14,6 +14,30 @@ import {launchUpdateFromVNode} from '../TreeBuilder';
|
|||
import {onlyUpdateChildVNodes} from '../vnode/VNodeCreator';
|
||||
import {setParentsChildShouldUpdate} from '../vnode/VNodeShouldUpdate';
|
||||
|
||||
// 从依赖中找到匹配context的VNode
|
||||
function matchDependencies(depContexts, context, vNode): boolean {
|
||||
for (let i = 0; i < depContexts.length; i++) {
|
||||
const contextItem = depContexts[i];
|
||||
if (contextItem === context) {
|
||||
// 匹配到了更新的context,需要创建update。
|
||||
if (vNode.tag === ClassComponent) {
|
||||
pushForceUpdate(vNode);
|
||||
}
|
||||
|
||||
vNode.shouldUpdate = true;
|
||||
|
||||
// 找到需要更新的节点,所以祖先节点都需要改为shouldUpdate为true
|
||||
setParentsChildShouldUpdate(vNode.parent);
|
||||
|
||||
vNode.isDepContextChange = true;
|
||||
// 由于我们已经找到匹配项,我们可以停止遍历依赖项列表。
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// 从当前子节点开始向下遍历,找到消费此context的组件,并更新
|
||||
function handleContextChange(processing: VNode, context: ContextType<any>): void {
|
||||
const vNode = processing.child;
|
||||
|
@ -24,15 +48,15 @@ function handleContextChange(processing: VNode, context: ContextType<any>): void
|
|||
let isMatch = false;
|
||||
|
||||
// 从vNode开始遍历
|
||||
travelVNodeTree(vNode, (node) => {
|
||||
travelVNodeTree(vNode, node => {
|
||||
const depContexts = node.depContexts;
|
||||
if (depContexts.length) {
|
||||
isMatch = matchDependencies(depContexts, context, node) ?? isMatch;
|
||||
}
|
||||
}, (node) => {
|
||||
}, node =>
|
||||
// 如果这是匹配的provider,则不要更深入地扫描
|
||||
return node.tag === ContextProvider && node.type === processing.type;
|
||||
}, processing);
|
||||
node.tag === ContextProvider && node.type === processing.type
|
||||
, processing);
|
||||
|
||||
// 找到了依赖context的子节点,触发一次更新
|
||||
if (isMatch) {
|
||||
|
@ -80,26 +104,3 @@ export function bubbleRender(processing: VNode) {
|
|||
resetContextCtx(processing);
|
||||
}
|
||||
|
||||
// 从依赖中找到匹配context的VNode
|
||||
function matchDependencies(depContexts, context, vNode): boolean {
|
||||
for (let i = 0; i < depContexts.length; i++) {
|
||||
const contextItem = depContexts[i];
|
||||
if (contextItem === context) {
|
||||
// 匹配到了更新的context,需要创建update。
|
||||
if (vNode.tag === ClassComponent) {
|
||||
pushForceUpdate(vNode);
|
||||
}
|
||||
|
||||
vNode.shouldUpdate = true;
|
||||
|
||||
// 找到需要更新的节点,所以祖先节点都需要改为shouldUpdate为true
|
||||
setParentsChildShouldUpdate(vNode.parent);
|
||||
|
||||
vNode.isDepContextChange = true;
|
||||
// 由于我们已经找到匹配项,我们可以停止遍历依赖项列表。
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -17,8 +17,55 @@ import {createVNodeChildren, markRef} from './BaseComponent';
|
|||
import {DomComponent, DomPortal, DomText} from '../vnode/VNodeTags';
|
||||
import {getFirstChild, travelVNodeTree} from '../vnode/VNodeUtils';
|
||||
|
||||
export function captureRender(processing: VNode): VNode | null {
|
||||
return captureDomComponent(processing);
|
||||
function updateDom(
|
||||
processing: VNode,
|
||||
type: any,
|
||||
newProps: Props,
|
||||
) {
|
||||
// 如果oldProps !== newProps,意味着存在更新,并且需要处理其相关的副作用
|
||||
const oldProps = processing.oldProps;
|
||||
if (oldProps === newProps) {
|
||||
// 如果props没有发生变化,即使它的children发生了变化,我们也不会改变它
|
||||
return;
|
||||
}
|
||||
|
||||
const dom: Element = processing.realNode;
|
||||
|
||||
const changeList = getPropChangeList(
|
||||
dom,
|
||||
type,
|
||||
oldProps,
|
||||
newProps,
|
||||
);
|
||||
processing.changeList = changeList;
|
||||
|
||||
// 输入类型的直接标记更新
|
||||
if (type === 'input' || type === 'textarea' || type === 'select' || type === 'option') {
|
||||
FlagUtils.markUpdate(processing);
|
||||
} else {
|
||||
// 其它的类型,数据有变化才标记更新
|
||||
if (changeList.length) {
|
||||
FlagUtils.markUpdate(processing);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 把dom类型的子节点append到parent dom中
|
||||
function appendAllChildren(parent: Element, processing: VNode) {
|
||||
const vNode = processing.child;
|
||||
if (vNode === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 向下递归它的子节点,查找所有终端节点。
|
||||
travelVNodeTree(vNode, node => {
|
||||
if (node.tag === DomComponent || node.tag === DomText) {
|
||||
appendChildElement(parent, node.realNode);
|
||||
}
|
||||
}, node =>
|
||||
// 已经append到父节点,或者是DomPortal都不需要处理child了
|
||||
node.tag === DomComponent || node.tag === DomText || node.tag === DomPortal
|
||||
, processing);
|
||||
}
|
||||
|
||||
export function bubbleRender(processing: VNode) {
|
||||
|
@ -86,53 +133,6 @@ function captureDomComponent(processing: VNode): VNode | null {
|
|||
return processing.child;
|
||||
}
|
||||
|
||||
// 把dom类型的子节点append到parent dom中
|
||||
function appendAllChildren(parent: Element, processing: VNode) {
|
||||
const vNode = processing.child;
|
||||
if (vNode === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 向下递归它的子节点,查找所有终端节点。
|
||||
travelVNodeTree(vNode, (node) => {
|
||||
if (node.tag === DomComponent || node.tag === DomText) {
|
||||
appendChildElement(parent, node.realNode);
|
||||
}
|
||||
}, (node) => {
|
||||
// 已经append到父节点,或者是DomPortal都不需要处理child了
|
||||
return node.tag === DomComponent || node.tag === DomText || node.tag === DomPortal;
|
||||
}, processing);
|
||||
}
|
||||
|
||||
function updateDom(
|
||||
processing: VNode,
|
||||
type: any,
|
||||
newProps: Props,
|
||||
) {
|
||||
// 如果oldProps !== newProps,意味着存在更新,并且需要处理其相关的副作用
|
||||
const oldProps = processing.oldProps;
|
||||
if (oldProps === newProps) {
|
||||
// 如果props没有发生变化,即使它的children发生了变化,我们也不会改变它
|
||||
return;
|
||||
}
|
||||
|
||||
const dom: Element = processing.realNode;
|
||||
|
||||
const changeList = getPropChangeList(
|
||||
dom,
|
||||
type,
|
||||
oldProps,
|
||||
newProps,
|
||||
);
|
||||
processing.changeList = changeList;
|
||||
|
||||
// 输入类型的直接标记更新
|
||||
if (type === 'input' || type === 'textarea' || type === 'select' || type === 'option') {
|
||||
FlagUtils.markUpdate(processing);
|
||||
} else {
|
||||
// 其它的类型,数据有变化才标记更新
|
||||
if (changeList.length) {
|
||||
FlagUtils.markUpdate(processing);
|
||||
}
|
||||
}
|
||||
export function captureRender(processing: VNode): VNode | null {
|
||||
return captureDomComponent(processing);
|
||||
}
|
||||
|
|
|
@ -4,10 +4,6 @@ import { createChildrenByDiff } from '../diff/nodeDiffComparator';
|
|||
import { createVNodeChildren } from './BaseComponent';
|
||||
import { prePortal } from '../../dom/DOMOperator';
|
||||
|
||||
export function captureRender(processing: VNode): VNode | null {
|
||||
return capturePortalComponent(processing);
|
||||
}
|
||||
|
||||
export function bubbleRender(processing: VNode) {
|
||||
resetNamespaceCtx(processing);
|
||||
|
||||
|
@ -27,3 +23,7 @@ function capturePortalComponent(processing: VNode) {
|
|||
}
|
||||
return processing.child;
|
||||
}
|
||||
|
||||
export function captureRender(processing: VNode): VNode | null {
|
||||
return capturePortalComponent(processing);
|
||||
}
|
||||
|
|
|
@ -13,23 +13,40 @@ import {onlyUpdateChildVNodes} from '../vnode/VNodeCreator';
|
|||
// 在useState, useReducer的时候,会触发state变化
|
||||
let stateChange = false;
|
||||
|
||||
export function captureRender(processing: VNode, shouldUpdate?: boolean): VNode | null {
|
||||
const Component = processing.type;
|
||||
const unresolvedProps = processing.props;
|
||||
const resolvedProps =
|
||||
processing.isLazyComponent
|
||||
? mergeDefaultProps(Component, unresolvedProps)
|
||||
: unresolvedProps;
|
||||
export function bubbleRender() {}
|
||||
|
||||
return captureFunctionComponent(
|
||||
processing,
|
||||
Component,
|
||||
resolvedProps,
|
||||
shouldUpdate
|
||||
);
|
||||
// 判断children是否可以复用
|
||||
function checkIfCanReuseChildren(processing: VNode, shouldUpdate?: boolean) {
|
||||
let isCanReuse = true;
|
||||
|
||||
if (!processing.isCreated) {
|
||||
const oldProps = processing.oldProps;
|
||||
const newProps = processing.props;
|
||||
|
||||
// 如果props或者context改变了
|
||||
if (oldProps !== newProps || getContextChangeCtx() || processing.isDepContextChange) {
|
||||
isCanReuse = false;
|
||||
} else {
|
||||
if (shouldUpdate && processing.suspenseChildThrow) {
|
||||
// 使用完后恢复
|
||||
processing.suspenseChildThrow = false;
|
||||
isCanReuse = false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
isCanReuse = false;
|
||||
}
|
||||
|
||||
return isCanReuse;
|
||||
}
|
||||
|
||||
export function bubbleRender() {}
|
||||
export function setStateChange(isUpdate) {
|
||||
stateChange = isUpdate;
|
||||
}
|
||||
|
||||
export function isStateChange() {
|
||||
return stateChange;
|
||||
}
|
||||
|
||||
export function captureFunctionComponent(
|
||||
processing: VNode,
|
||||
|
@ -66,35 +83,19 @@ export function captureFunctionComponent(
|
|||
return processing.child;
|
||||
}
|
||||
|
||||
// 判断children是否可以复用
|
||||
function checkIfCanReuseChildren(processing: VNode, shouldUpdate?: boolean) {
|
||||
let isCanReuse = true;
|
||||
export function captureRender(processing: VNode, shouldUpdate?: boolean): VNode | null {
|
||||
const Component = processing.type;
|
||||
const unresolvedProps = processing.props;
|
||||
const resolvedProps =
|
||||
processing.isLazyComponent
|
||||
? mergeDefaultProps(Component, unresolvedProps)
|
||||
: unresolvedProps;
|
||||
|
||||
if (!processing.isCreated) {
|
||||
const oldProps = processing.oldProps;
|
||||
const newProps = processing.props;
|
||||
|
||||
// 如果props或者context改变了
|
||||
if (oldProps !== newProps || getContextChangeCtx() || processing.isDepContextChange) {
|
||||
isCanReuse = false;
|
||||
} else {
|
||||
if (shouldUpdate && processing.suspenseChildThrow) {
|
||||
// 使用完后恢复
|
||||
processing.suspenseChildThrow = false;
|
||||
isCanReuse = false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
isCanReuse = false;
|
||||
}
|
||||
|
||||
return isCanReuse;
|
||||
return captureFunctionComponent(
|
||||
processing,
|
||||
Component,
|
||||
resolvedProps,
|
||||
shouldUpdate
|
||||
);
|
||||
}
|
||||
|
||||
export function setStateChange(isUpdate) {
|
||||
stateChange = isUpdate;
|
||||
}
|
||||
|
||||
export function isStateChange() {
|
||||
return stateChange;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue