Match-id-99bbd5ad3faaa464940d22311dc541b33c789ab4

This commit is contained in:
* 2022-01-25 15:07:16 +08:00 committed by *
commit 569db9a834
15 changed files with 271 additions and 272 deletions

View File

@ -10,30 +10,6 @@ import {findDOMByClassInst} from '../renderer/vnode/VNodeUtils';
import {TreeRoot} from '../renderer/vnode/VNodeTags'; import {TreeRoot} from '../renderer/vnode/VNodeTags';
import {Callback} from '../renderer/UpdateHandler'; import {Callback} from '../renderer/UpdateHandler';
function executeRender(
children: any,
container: Container,
callback?: Callback,
) {
let treeRoot = container._treeRoot;
if (!treeRoot) {
treeRoot = createRoot(children, container, callback);
} else { // container被render过
if (typeof callback === 'function') {
const cb = callback;
callback = function () {
const instance = getFirstCustomDom(treeRoot);
cb.call(instance);
};
}
// 执行更新操作
startUpdate(children, treeRoot, callback);
}
return getFirstCustomDom(treeRoot);
}
function createRoot(children: any, container: Container, callback?: Callback) { function createRoot(children: any, container: Container, callback?: Callback) {
// 清空容器 // 清空容器
let child = container.lastChild; let child = container.lastChild;
@ -66,7 +42,31 @@ function createRoot(children: any, container: Container, callback?: Callback) {
return treeRoot; return treeRoot;
} }
function findDOMNode(domOrEle: Element): null | Element | Text { function executeRender(
children: any,
container: Container,
callback?: Callback,
) {
let treeRoot = container._treeRoot;
if (!treeRoot) {
treeRoot = createRoot(children, container, callback);
} else { // container被render过
if (typeof callback === 'function') {
const cb = callback;
callback = function () {
const instance = getFirstCustomDom(treeRoot);
cb.call(instance);
};
}
// 执行更新操作
startUpdate(children, treeRoot, callback);
}
return getFirstCustomDom(treeRoot);
}
function findDOMNode(domOrEle?: Element): null | Element | Text {
if (domOrEle == null) { if (domOrEle == null) {
return null; return null;
} }

View File

@ -72,7 +72,7 @@ export function getNearestVNode(dom: Node): null | VNode {
} }
// 获取 vNode 上的属性相关信息 // 获取 vNode 上的属性相关信息
export function getVNodeProps(dom: Element | Text): Props { export function getVNodeProps(dom: Element | Text): Props | null{
return dom[internalKeys.props] || null; return dom[internalKeys.props] || null;
} }
@ -93,7 +93,8 @@ export function getEventListeners(dom: EventTarget): Set<string> {
export function getEventToListenerMap(target: EventTarget): Map<string, EventListener> { export function getEventToListenerMap(target: EventTarget): Map<string, EventListener> {
let eventsMap = target[internalKeys.nonDelegatedEvents]; let eventsMap = target[internalKeys.nonDelegatedEvents];
if (!eventsMap) { if (!eventsMap) {
eventsMap = target[internalKeys.nonDelegatedEvents] = new Map(); eventsMap = new Map();
target[internalKeys.nonDelegatedEvents] = eventsMap;
} }
return eventsMap; return eventsMap;
} }

View File

@ -5,13 +5,13 @@ import {
import { import {
createDom, createDom,
} from './utils/DomCreator'; } from './utils/DomCreator';
import {getSelectionInfo, resetSelectionRange, selectionData} from './SelectionRangeHandler'; import { getSelectionInfo, resetSelectionRange, selectionData } from './SelectionRangeHandler';
import {isElement, isComment, isDocument, isDocumentFragment, getDomTag, shouldAutoFocus} from './utils/Common'; import { isElement, isComment, isDocument, isDocumentFragment, getDomTag, shouldAutoFocus } from './utils/Common';
import {NSS} from './utils/DomCreator'; import { NSS } from './utils/DomCreator';
import {adjustStyleValue} from './DOMPropertiesHandler/StyleHandler'; import { adjustStyleValue } from './DOMPropertiesHandler/StyleHandler';
import {listenDelegatedEvents} from '../event/EventBinding'; import { listenDelegatedEvents } from '../event/EventBinding';
import type {VNode} from '../renderer/Types'; import type { VNode } from '../renderer/Types';
import { import {
setInitValue, setInitValue,
getPropsWithoutValue, getPropsWithoutValue,
@ -21,10 +21,10 @@ import {
compareProps, compareProps,
setDomProps, updateDomProps setDomProps, updateDomProps
} from './DOMPropertiesHandler/DOMPropertiesHandler'; } from './DOMPropertiesHandler/DOMPropertiesHandler';
import {isNativeElement, validateProps} from './validators/ValidateProps'; import { isNativeElement, validateProps } from './validators/ValidateProps';
import {watchValueChange} from './valueHandler/ValueChangeHandler'; import { watchValueChange } from './valueHandler/ValueChangeHandler';
import {DomComponent, DomText} from '../renderer/vnode/VNodeTags'; import { DomComponent, DomText } from '../renderer/vnode/VNodeTags';
import {updateCommonProp} from './DOMPropertiesHandler/UpdateCommonProp'; import { updateCommonProp } from './DOMPropertiesHandler/UpdateCommonProp';
export type Props = { export type Props = {
autoFocus?: boolean; autoFocus?: boolean;
@ -54,14 +54,8 @@ function getChildNS(parentNS: string | null, tagName: string): string {
} }
// 获取容器 // 获取容器
export function getNSCtx(dom: Container, parentNS: string, type: string): string { export function getNSCtx(dom?: Container, parentNS: string, type: string): string {
let namespace; return dom ? getChildNS(dom.namespaceURI ?? null, dom.nodeName) : getChildNS(parentNS, type);
if (dom) {
namespace = getChildNS(dom.namespaceURI ?? null, dom.nodeName);
} else {
namespace = getChildNS(parentNS, type);
}
return namespace;
} }
export function prepareForSubmit(): void { export function prepareForSubmit(): void {
@ -156,7 +150,7 @@ export function newTextDom(
// 提交vNode的类型为Component或者Text的更新 // 提交vNode的类型为Component或者Text的更新
export function submitDomUpdate(tag: string, vNode: VNode) { export function submitDomUpdate(tag: string, vNode: VNode) {
const newProps = vNode.props; const newProps = vNode.props;
const element: Element = vNode.realNode; const element: Element | null = vNode.realNode;
if (tag === DomComponent) { if (tag === DomComponent) {
// DomComponent类型 // DomComponent类型
@ -179,9 +173,11 @@ export function submitDomUpdate(tag: string, vNode: VNode) {
} }
} }
} else if (tag === DomText) { } else if (tag === DomText) {
if (element != null) {
// text类型 // text类型
element.textContent = newProps; element.textContent = newProps;
} }
}
} }
export function clearText(dom: Element): void { export function clearText(dom: Element): void {

View File

@ -8,6 +8,27 @@ import {
} from '../../event/EventBinding'; } from '../../event/EventBinding';
import { isEventProp, isNativeElement } from '../validators/ValidateProps'; import { isEventProp, isNativeElement } from '../validators/ValidateProps';
function updateOneProp(dom, propName, propVal, isNativeTag, isInit?: boolean) {
if (propName === 'style') {
setStyles(dom, propVal);
} else if (propName === 'dangerouslySetInnerHTML') {
dom.innerHTML = propVal.__html;
} else if (propName === 'children') { // 只处理纯文本子节点其他children在VNode树中处理
if (typeof propVal === 'string' || typeof propVal === 'number') {
dom.textContent = String(propVal);
}
} else if (isEventProp(propName)) {
// 事件监听属性处理
if (!allDelegatedHorizonEvents.has(propName)) {
listenNonDelegatedEvent(propName, dom, propVal);
}
} else {
if (!isInit || (isInit && propVal != null)) {
updateCommonProp(dom, propName, propVal, isNativeTag);
}
}
}
// 初始化DOM属性 // 初始化DOM属性
export function setDomProps( export function setDomProps(
tagName: string, tagName: string,
@ -38,27 +59,6 @@ export function updateDomProps(
} }
} }
function updateOneProp(dom, propName, propVal, isNativeTag, isInit?: boolean) {
if (propName === 'style') {
setStyles(dom, propVal);
} else if (propName === 'dangerouslySetInnerHTML') {
dom.innerHTML = propVal.__html;
} else if (propName === 'children') { // 只处理纯文本子节点其他children在VNode树中处理
if (typeof propVal === 'string' || typeof propVal === 'number') {
dom.textContent = String(propVal);
}
} else if (isEventProp(propName)) {
// 事件监听属性处理
if (!allDelegatedHorizonEvents.has(propName)) {
listenNonDelegatedEvent(propName, dom, propVal);
}
} else {
if (!isInit || (isInit && propVal != null)) {
updateCommonProp(dom, propName, propVal, isNativeTag);
}
}
}
// 找出两个 DOM 属性的差别,生成需要更新的属性集合 // 找出两个 DOM 属性的差别,生成需要更新的属性集合
export function compareProps( export function compareProps(
oldProps: Object, oldProps: Object,

View File

@ -122,7 +122,9 @@ function getProcessListenersFacade(
)); ));
} }
if (nativeEvtName === 'compositionend' || nativeEvtName === 'compositionstart' || nativeEvtName === 'compositionupdate') { if (nativeEvtName === 'compositionend' ||
nativeEvtName === 'compositionstart' ||
nativeEvtName === 'compositionupdate') {
processingListenerList = processingListenerList.concat(getCompositionListeners( processingListenerList = processingListenerList.concat(getCompositionListeners(
nativeEvtName, nativeEvtName,
nativeEvent, nativeEvent,
@ -183,13 +185,14 @@ export function handleEventMain(
// 有事件正在执行,同步执行事件 // 有事件正在执行,同步执行事件
if (isInEventsExecution) { if (isInEventsExecution) {
return triggerHorizonEvents(nativeEvtName, isCapture, nativeEvent, rootVNode); triggerHorizonEvents(nativeEvtName, isCapture, nativeEvent, rootVNode);
return;
} }
// 没有事件在执行,经过调度再执行事件 // 没有事件在执行,经过调度再执行事件
isInEventsExecution = true; isInEventsExecution = true;
try { try {
return asyncUpdates(() => asyncUpdates(() =>
triggerHorizonEvents( triggerHorizonEvents(
nativeEvtName, nativeEvtName,
isCapture, isCapture,

View File

@ -5,15 +5,6 @@ import {handleEventMain} from './HorizonEventMain';
import {runDiscreteUpdates} from '../renderer/Renderer'; import {runDiscreteUpdates} from '../renderer/Renderer';
import {getEventTarget} from './utils'; import {getEventTarget} from './utils';
// 生成委托事件的监听方法
export function createCustomEventListener(
target: EventTarget,
nativeEvtName: string,
isCapture: boolean,
): EventListener {
return triggerDelegatedEvent.bind(null, nativeEvtName, isCapture, target);
}
// 触发委托事件 // 触发委托事件
function triggerDelegatedEvent( function triggerDelegatedEvent(
nativeEvtName: string, nativeEvtName: string,
@ -39,3 +30,12 @@ function triggerDelegatedEvent(
} }
handleEventMain(nativeEvtName, isCapture, nativeEvent, targetVNode, targetDom); handleEventMain(nativeEvtName, isCapture, nativeEvent, targetVNode, targetDom);
} }
// 生成委托事件的监听方法
export function createCustomEventListener(
target: EventTarget,
nativeEvtName: string,
isCapture: boolean,
): EventListener {
return triggerDelegatedEvent.bind(null, nativeEvtName, isCapture, target);
}

View File

@ -4,6 +4,48 @@
import {VNode} from '../../renderer/Types'; import {VNode} from '../../renderer/Types';
// 从原生事件中复制属性到自定义事件中
function extendAttribute(target, source) {
const attributes = [
// AnimationEvent
'animationName', 'elapsedTime', 'pseudoElement',
// CompositionEvent、InputEvent
'data',
// DragEvent
'dataTransfer',
// FocusEvent
'relatedTarget',
// KeyboardEvent
'key', 'keyCode', 'charCode', 'code', 'location', 'ctrlKey', 'shiftKey',
'altKey', 'metaKey', 'repeat', 'locale', 'getModifierState', 'clipboardData',
// MouseEvent
'button', 'buttons', 'clientX', 'clientY', 'movementX', 'movementY',
'pageX', 'pageY', 'screenX', 'screenY', 'currentTarget',
// PointerEvent
'pointerId', 'width', 'height', 'pressure', 'tangentialPressure',
'tiltX', 'tiltY', 'twist', 'pointerType', 'isPrimary',
// TouchEvent
'touches', 'targetTouches', 'changedTouches',
// TransitionEvent
'propertyName',
// UIEvent
'view', 'detail',
// WheelEvent
'deltaX', 'deltaY', 'deltaZ', 'deltaMode',
];
attributes.forEach(attr => {
if (typeof source[attr] !== 'undefined') {
if (typeof source[attr] === 'function') {
target[attr] = function() {
return source[attr].apply(source, arguments);
};
} else {
target[attr] = source[attr];
}
}
})
}
export class CustomBaseEvent { export class CustomBaseEvent {
data: string; data: string;
@ -79,46 +121,3 @@ export class CustomBaseEvent {
this.isPropagationStopped = () => true; this.isPropagationStopped = () => true;
} }
} }
// 从原生事件中复制属性到自定义事件中
function extendAttribute(target, source) {
const attributes = [
// AnimationEvent
'animationName', 'elapsedTime', 'pseudoElement',
// CompositionEvent、InputEvent
'data',
// DragEvent
'dataTransfer',
// FocusEvent
'relatedTarget',
// KeyboardEvent
'key', 'keyCode', 'charCode', 'code', 'location', 'ctrlKey', 'shiftKey',
'altKey', 'metaKey', 'repeat', 'locale', 'getModifierState', 'clipboardData',
// MouseEvent
'button', 'buttons', 'clientX', 'clientY', 'movementX', 'movementY',
'pageX', 'pageY', 'screenX', 'screenY', 'currentTarget',
// PointerEvent
'pointerId', 'width', 'height', 'pressure', 'tangentialPressure',
'tiltX', 'tiltY', 'twist', 'pointerType', 'isPrimary',
// TouchEvent
'touches', 'targetTouches', 'changedTouches',
// TransitionEvent
'propertyName',
// UIEvent
'view', 'detail',
// WheelEvent
'deltaX', 'deltaY', 'deltaZ', 'deltaMode',
];
attributes.forEach(attr => {
if (typeof source[attr] !== 'undefined') {
if (typeof source[attr] === 'function') {
target[attr] = function() {
return source[attr].apply(source, arguments);
};
} else {
target[attr] = source[attr];
}
}
})
}

View File

@ -9,7 +9,7 @@ const SPACE_CHAR = String.fromCharCode(CHAR_CODE_SPACE);
function getInputCharsByNative( function getInputCharsByNative(
eventName: string, eventName: string,
nativeEvent: any, nativeEvent: any,
): string | void { ): string | null {
if (eventName === 'compositionend') { if (eventName === 'compositionend') {
return (nativeEvent.detail && nativeEvent.detail.data) || null; return (nativeEvent.detail && nativeEvent.detail.data) || null;
} }

View File

@ -13,7 +13,7 @@ const horizonEventName = 'onSelect'
let currentElement = null; let currentElement = null;
let currentVNode = null; let currentVNode = null;
let lastSelection = null; let lastSelection: Selection | null = null;
function initTargetCache(dom, vNode) { function initTargetCache(dom, vNode) {
if (isTextInputElement(dom) || dom.contentEditable === 'true') { if (isTextInputElement(dom) || dom.contentEditable === 'true') {
@ -85,7 +85,7 @@ export function getListeners(
target: null | EventTarget, target: null | EventTarget,
): ProcessingListenerList { ): ProcessingListenerList {
const targetNode = vNode ? getDom(vNode) : window; const targetNode = vNode ? getDom(vNode) : window;
let eventUnitList = []; let eventUnitList: ProcessingListenerList = [];
switch (name) { switch (name) {
case 'focusin': case 'focusin':
initTargetCache(targetNode, vNode); initTargetCache(targetNode, vNode);

View File

@ -31,7 +31,7 @@ let ctxOldPreviousContext: Object = {};
// capture阶段设置 // capture阶段设置
function setNamespaceCtx(vNode: VNode, dom?: Container) { function setNamespaceCtx(vNode: VNode, dom?: Container) {
const nextContext = getNSCtx(dom, ctxNamespace, vNode.type); const nextContext = getNSCtx(ctxNamespace, vNode.type, dom);
vNode.setContext(CTX_NAMESPACE, ctxNamespace); vNode.setContext(CTX_NAMESPACE, ctxNamespace);
ctxNamespace = nextContext; ctxNamespace = nextContext;

View File

@ -10,7 +10,18 @@ import {
cacheOldCtx, cacheOldCtx,
} from '../components/context/CompatibleContext'; } from '../components/context/CompatibleContext';
export function captureRender(processing: VNode): Array<VNode> | null { function captureIncompleteClassComponent(processing, Component, nextProps) {
processing.tag = ClassComponent;
const hasOldContext = isOldProvider(Component);
cacheOldCtx(processing, hasOldContext);
resetDepContexts(processing);
return getIncompleteClassComponent(Component, processing, nextProps);
}
export function captureRender(processing: VNode): VNode | null {
const Component = processing.type; const Component = processing.type;
const unresolvedProps = processing.props; const unresolvedProps = processing.props;
const resolvedProps = const resolvedProps =
@ -28,14 +39,3 @@ export function bubbleRender(processing: VNode) {
resetOldCtx(processing); resetOldCtx(processing);
} }
} }
function captureIncompleteClassComponent(processing, Component, nextProps) {
processing.tag = ClassComponent;
const hasOldContext = isOldProvider(Component);
cacheOldCtx(processing, hasOldContext);
resetDepContexts(processing);
return getIncompleteClassComponent(Component, processing, nextProps);
}

View File

@ -13,10 +13,6 @@ 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 {
return captureLazyComponent(processing, processing.type, shouldUpdate);
}
export function bubbleRender() { } export function bubbleRender() { }
const LazyRendererMap = { const LazyRendererMap = {
@ -26,6 +22,20 @@ const LazyRendererMap = {
[MemoComponent]: captureMemoComponent, [MemoComponent]: captureMemoComponent,
}; };
export function mergeDefaultProps(Component: any, props: object): object {
if (Component && Component.defaultProps) {
const clonedProps = { ...props };
const defaultProps = Component.defaultProps;
Object.keys(defaultProps).forEach(key => {
if (clonedProps[key] === undefined) {
clonedProps[key] = defaultProps[key];
}
});
return clonedProps;
}
return props;
}
function captureLazyComponent( function captureLazyComponent(
processing, processing,
lazyComponent, lazyComponent,
@ -43,7 +53,8 @@ function captureLazyComponent(
// 加载得到的Component存在type中 // 加载得到的Component存在type中
processing.type = Component; processing.type = Component;
const lazyVNodeTag = processing.tag = getLazyVNodeTag(Component); const lazyVNodeTag = getLazyVNodeTag(Component);
processing.tag = lazyVNodeTag;
const lazyVNodeProps = mergeDefaultProps(Component, processing.props); const lazyVNodeProps = mergeDefaultProps(Component, processing.props);
const lazyRender = LazyRendererMap[lazyVNodeTag]; const lazyRender = LazyRendererMap[lazyVNodeTag];
@ -68,16 +79,6 @@ function captureLazyComponent(
} }
} }
export function mergeDefaultProps(Component: any, props: object): object { export function captureRender(processing: VNode, shouldUpdate: boolean): VNode | null {
if (Component && Component.defaultProps) { return captureLazyComponent(processing, processing.type, shouldUpdate);
const clonedProps = { ...props };
const defaultProps = Component.defaultProps;
Object.keys(defaultProps).forEach(key => {
if (clonedProps[key] === undefined) {
clonedProps[key] = defaultProps[key];
}
});
return clonedProps;
}
return props;
} }

View File

@ -19,73 +19,36 @@ export enum SuspenseChildStatus {
ShowFallback = 'showFallback', ShowFallback = 'showFallback',
} }
export function captureRender(processing: VNode, shouldUpdate: boolean): Array<VNode> | VNode | null { // 创建fallback子节点
if ( function createFallback(processing: VNode, fallbackChildren) {
!processing.isCreated &&
processing.oldProps === processing.props &&
!getContextChangeCtx() &&
!shouldUpdate
) {
if (processing.suspenseChildStatus === SuspenseChildStatus.ShowFallback) {
// 当显示fallback时suspense的子组件要更新
return updateFallback(processing);
}
return onlyUpdateChildVNodes(processing);
}
return captureSuspenseComponent(processing);
}
function updateFallback(processing: VNode): Array<VNode> | VNode | null {
const childFragment: VNode = processing.child; const childFragment: VNode = processing.child;
let fallbackFragment;
if (childFragment.childShouldUpdate) {
if (processing.promiseResolve) {
// promise已完成展示promise返回的新节点
return captureSuspenseComponent(processing);
} else {
// promise未完成继续显示fallback不需要继续刷新子节点
const fallbackFragment: VNode = processing.child.next;
childFragment.childShouldUpdate = false; childFragment.childShouldUpdate = false;
fallbackFragment.childShouldUpdate = false;
return null; if (!processing.isCreated) {
const oldFallbackFragment: VNode | null = processing.oldChild ? processing.oldChild.next : null;
if (oldFallbackFragment !== null) {
fallbackFragment = updateVNode(oldFallbackFragment, fallbackChildren);
} else {
fallbackFragment = createVNode(Fragment, null, fallbackChildren);
FlagUtils.markAddition(fallbackFragment);
} }
} else { } else {
const children = onlyUpdateChildVNodes(processing); // 创建
fallbackFragment = createVNode(Fragment, null, fallbackChildren);
if (children !== null) {
// child不需要更新跳过child处理fallback
return children[1];
} else {
return null;
}
}
}
export function bubbleRender(processing: VNode) {
if (processing.suspenseChildStatus === SuspenseChildStatus.ShowFallback
|| (!processing.isCreated && processing.oldSuspenseChildStatus === SuspenseChildStatus.ShowFallback)
) {
FlagUtils.markUpdate(processing);
} }
return null; processing.child = childFragment;
} childFragment.next = fallbackFragment;
childFragment.parent = processing;
fallbackFragment.parent = processing;
fallbackFragment.eIndex = 1;
fallbackFragment.cIndex = 1;
updateVNodePath(fallbackFragment);
processing.suspenseChildStatus = SuspenseChildStatus.ShowFallback;
export function captureSuspenseComponent(processing: VNode) { return fallbackFragment;
const nextProps = processing.props;
// suspense被捕获后需要展示fallback
const showFallback = processing.suspenseDidCapture;
if (showFallback) {
processing.suspenseDidCapture = false;
const nextFallbackChildren = nextProps.fallback;
return createFallback(processing, nextFallbackChildren);
} else {
const newChildren = nextProps.children;
return createSuspenseChildren(processing, newChildren);
}
} }
// 创建子节点 // 创建子节点
@ -120,36 +83,77 @@ function createSuspenseChildren(processing: VNode, newChildren) {
return processing.child; return processing.child;
} }
// 创建fallback子节点 export function captureSuspenseComponent(processing: VNode) {
function createFallback(processing: VNode, fallbackChildren) { const nextProps = processing.props;
const childFragment: VNode = processing.child;
let fallbackFragment; // suspense被捕获后需要展示fallback
const showFallback = processing.suspenseDidCapture;
if (showFallback) {
processing.suspenseDidCapture = false;
const nextFallbackChildren = nextProps.fallback;
return createFallback(processing, nextFallbackChildren);
} else {
const newChildren = nextProps.children;
return createSuspenseChildren(processing, newChildren);
}
}
function updateFallback(processing: VNode): Array<VNode> | VNode | null {
const childFragment: VNode | null= processing.child;
if (childFragment?.childShouldUpdate) {
if (processing.promiseResolve) {
// promise已完成展示promise返回的新节点
return captureSuspenseComponent(processing);
} else {
// promise未完成继续显示fallback不需要继续刷新子节点
const fallbackFragment: VNode = processing.child.next;
childFragment.childShouldUpdate = false; childFragment.childShouldUpdate = false;
fallbackFragment.childShouldUpdate = false;
if (!processing.isCreated) { return null;
const oldFallbackFragment: VNode | null = processing.oldChild ? processing.oldChild.next : null;
if (oldFallbackFragment !== null) {
fallbackFragment = updateVNode(oldFallbackFragment, fallbackChildren);
} else {
fallbackFragment = createVNode(Fragment, null, fallbackChildren);
FlagUtils.markAddition(fallbackFragment);
} }
} else { } else {
// 创建 const children = onlyUpdateChildVNodes(processing);
fallbackFragment = createVNode(Fragment, null, fallbackChildren);
if (children !== null) {
// child不需要更新跳过child处理fallback
return children[1];
} else {
return null;
}
}
}
export function captureRender(processing: VNode, shouldUpdate: boolean): Array<VNode> | VNode | null {
if (
!processing.isCreated &&
processing.oldProps === processing.props &&
!getContextChangeCtx() &&
!shouldUpdate
) {
if (processing.suspenseChildStatus === SuspenseChildStatus.ShowFallback) {
// 当显示fallback时suspense的子组件要更新
return updateFallback(processing);
}
return onlyUpdateChildVNodes(processing);
} }
processing.child = childFragment; return captureSuspenseComponent(processing);
childFragment.next = fallbackFragment; }
childFragment.parent = processing;
fallbackFragment.parent = processing;
fallbackFragment.eIndex = 1;
fallbackFragment.cIndex = 1;
updateVNodePath(fallbackFragment);
processing.suspenseChildStatus = SuspenseChildStatus.ShowFallback;
return fallbackFragment; export function bubbleRender(processing: VNode) {
if (processing.suspenseChildStatus === SuspenseChildStatus.ShowFallback
|| (!processing.isCreated && processing.oldSuspenseChildStatus === SuspenseChildStatus.ShowFallback)
) {
FlagUtils.markUpdate(processing);
}
return null;
}
function canCapturePromise(vNode: VNode | null): boolean {
return vNode?.suspenseChildStatus !== SuspenseChildStatus.ShowFallback && vNode?.props.fallback !== undefined;
} }
// 处理Suspense子组件抛出的promise // 处理Suspense子组件抛出的promise
@ -196,36 +200,8 @@ export function handleSuspenseChildThrowError(parent: VNode, processing: VNode,
return false; return false;
} }
function canCapturePromise(vNode: VNode): boolean {
return vNode.suspenseChildStatus !== SuspenseChildStatus.ShowFallback && vNode.props.fallback !== undefined;
}
const PossiblyWeakSet = typeof WeakSet === 'function' ? WeakSet : Set; const PossiblyWeakSet = typeof WeakSet === 'function' ? WeakSet : Set;
// 对于每个promise添加一个侦听器以便当它resolve时重新渲染
export function listenToPromise(suspenseVNode: VNode) {
const promises: Set<PromiseType<any>> | null = suspenseVNode.suspensePromises;
if (promises !== null) {
suspenseVNode.suspensePromises = null;
// 记录已经监听的 promise
let promiseCache = suspenseVNode.realNode;
if (promiseCache === null) {
// @ts-ignore
promiseCache = suspenseVNode.realNode = new PossiblyWeakSet();
}
promises.forEach(promise => {
const resole = resolvePromise.bind(null, suspenseVNode, promise);
if (!promiseCache.has(promise)) {
promiseCache.add(promise);
// 监听promise
promise.then(resole, resole);
}
});
}
}
function resolvePromise(suspenseVNode: VNode, promise: PromiseType<any>) { function resolvePromise(suspenseVNode: VNode, promise: PromiseType<any>) {
const promiseCache = suspenseVNode.realNode; const promiseCache = suspenseVNode.realNode;
if (promiseCache !== null) { if (promiseCache !== null) {
@ -238,4 +214,27 @@ function resolvePromise(suspenseVNode: VNode, promise: PromiseType<any>) {
} }
} }
// 对于每个promise添加一个侦听器以便当它resolve时重新渲染
export function listenToPromise(suspenseVNode: VNode) {
const promises: Set<PromiseType<any>> | null = suspenseVNode.suspensePromises;
if (promises !== null) {
suspenseVNode.suspensePromises = null;
// 记录已经监听的 promise
let promiseCache = suspenseVNode.realNode;
if (promiseCache === null) {
// @ts-ignore
promiseCache = new PossiblyWeakSet();
suspenseVNode.realNode = new PossiblyWeakSet();
}
promises.forEach(promise => {
const resole = resolvePromise.bind(null, suspenseVNode, promise);
if (!promiseCache.has(promise)) {
promiseCache.add(promise);
// 监听promise
promise.then(resole, resole);
}
});
}
}

View File

@ -6,10 +6,6 @@ import {resetNamespaceCtx, setNamespaceCtx} from '../ContextSaver';
import {resetOldCtx} from '../components/context/CompatibleContext'; import {resetOldCtx} from '../components/context/CompatibleContext';
import {onlyUpdateChildVNodes} from '../vnode/VNodeCreator'; import {onlyUpdateChildVNodes} from '../vnode/VNodeCreator';
export function captureRender(processing: VNode): VNode | null {
return updateTreeRoot(processing);
}
export function bubbleRender(processing: VNode) { export function bubbleRender(processing: VNode) {
resetNamespaceCtx(processing); resetNamespaceCtx(processing);
resetOldCtx(processing); resetOldCtx(processing);
@ -40,3 +36,7 @@ function updateTreeRoot(processing) {
processing.child = createVNodeChildren(processing, newElement); processing.child = createVNodeChildren(processing, newElement);
return processing.child; return processing.child;
} }
export function captureRender(processing: VNode): VNode | null {
return updateTreeRoot(processing);
}

View File

@ -1,7 +1,7 @@
import type { VNode } from '../../Types'; import type { VNode } from '../../Types';
import type { Callback } from '../../UpdateHandler'; import type { Callback } from '../../UpdateHandler';
import {shallowCompare} from '../../utils/compare'; import { shallowCompare } from '../../utils/compare';
import { import {
pushUpdate, pushUpdate,
newUpdate, newUpdate,
@ -40,7 +40,7 @@ function changeStateContent(type: UpdateState, content: object, callback: Callba
if (type === UpdateState.Update || type === UpdateState.Override) { if (type === UpdateState.Update || type === UpdateState.Override) {
update.content = content; update.content = content;
} }
if (callback !== undefined && callback !== null) { if (callback) {
update.callback = callback; update.callback = callback;
} }