react/packages/react-reconciler/src/ReactFiberRoot.old.js

212 lines
6.7 KiB
JavaScript

/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
*/
import type {FiberRoot, SuspenseHydrationCallbacks} from './ReactInternalTypes';
import type {ExpirationTime} from './ReactFiberExpirationTime.old';
import type {RootTag} from './ReactRootTags';
import {noTimeout} from './ReactFiberHostConfig';
import {createHostRootFiber} from './ReactFiber.old';
import {NoWork} from './ReactFiberExpirationTime.old';
import {
enableSchedulerTracing,
enableSuspenseCallback,
} from 'shared/ReactFeatureFlags';
import {unstable_getThreadID} from 'scheduler/tracing';
import {NoPriority} from './SchedulerWithReactIntegration.old';
import {initializeUpdateQueue} from './ReactUpdateQueue.old';
import {clearPendingUpdates as clearPendingMutableSourceUpdates} from './ReactMutableSource.old';
import {LegacyRoot, BlockingRoot, ConcurrentRoot} from './ReactRootTags';
function FiberRootNode(containerInfo, tag, hydrate) {
this.tag = tag;
this.current = null;
this.containerInfo = containerInfo;
this.pendingChildren = null;
this.pingCache = null;
this.finishedExpirationTime = NoWork;
this.finishedWork = null;
this.timeoutHandle = noTimeout;
this.context = null;
this.pendingContext = null;
this.hydrate = hydrate;
this.callbackNode = null;
this.callbackPriority_old = NoPriority;
this.firstPendingTime = NoWork;
this.lastPendingTime = NoWork;
this.firstSuspendedTime = NoWork;
this.lastSuspendedTime = NoWork;
this.nextKnownPendingLevel = NoWork;
this.lastPingedTime = NoWork;
this.lastExpiredTime = NoWork;
this.mutableSourceLastPendingUpdateTime = NoWork;
if (enableSchedulerTracing) {
this.interactionThreadID = unstable_getThreadID();
this.memoizedInteractions = new Set();
this.pendingInteractionMap_old = new Map();
}
if (enableSuspenseCallback) {
this.hydrationCallbacks = null;
}
if (__DEV__) {
switch (tag) {
case BlockingRoot:
this._debugRootType = 'createBlockingRoot()';
break;
case ConcurrentRoot:
this._debugRootType = 'createRoot()';
break;
case LegacyRoot:
this._debugRootType = 'createLegacyRoot()';
break;
}
}
}
export function createFiberRoot(
containerInfo: any,
tag: RootTag,
hydrate: boolean,
hydrationCallbacks: null | SuspenseHydrationCallbacks,
): FiberRoot {
const root: FiberRoot = (new FiberRootNode(containerInfo, tag, hydrate): any);
if (enableSuspenseCallback) {
root.hydrationCallbacks = hydrationCallbacks;
}
// Cyclic construction. This cheats the type system right now because
// stateNode is any.
const uninitializedFiber = createHostRootFiber(tag);
root.current = uninitializedFiber;
uninitializedFiber.stateNode = root;
initializeUpdateQueue(uninitializedFiber);
return root;
}
export function isRootSuspendedAtTime(
root: FiberRoot,
expirationTime: ExpirationTime,
): boolean {
const firstSuspendedTime = root.firstSuspendedTime;
const lastSuspendedTime = root.lastSuspendedTime;
return (
firstSuspendedTime !== NoWork &&
firstSuspendedTime >= expirationTime &&
lastSuspendedTime <= expirationTime
);
}
export function markRootSuspendedAtTime(
root: FiberRoot,
expirationTime: ExpirationTime,
): void {
const firstSuspendedTime = root.firstSuspendedTime;
const lastSuspendedTime = root.lastSuspendedTime;
if (firstSuspendedTime < expirationTime) {
root.firstSuspendedTime = expirationTime;
}
if (lastSuspendedTime > expirationTime || firstSuspendedTime === NoWork) {
root.lastSuspendedTime = expirationTime;
}
if (expirationTime <= root.lastPingedTime) {
root.lastPingedTime = NoWork;
}
if (expirationTime <= root.lastExpiredTime) {
root.lastExpiredTime = NoWork;
}
}
export function markRootUpdatedAtTime(
root: FiberRoot,
expirationTime: ExpirationTime,
): void {
// Update the range of pending times
const firstPendingTime = root.firstPendingTime;
if (expirationTime > firstPendingTime) {
root.firstPendingTime = expirationTime;
}
const lastPendingTime = root.lastPendingTime;
if (lastPendingTime === NoWork || expirationTime < lastPendingTime) {
root.lastPendingTime = expirationTime;
}
// Update the range of suspended times. Treat everything lower priority or
// equal to this update as unsuspended.
const firstSuspendedTime = root.firstSuspendedTime;
if (firstSuspendedTime !== NoWork) {
if (expirationTime >= firstSuspendedTime) {
// The entire suspended range is now unsuspended.
root.firstSuspendedTime = root.lastSuspendedTime = root.nextKnownPendingLevel = NoWork;
} else if (expirationTime >= root.lastSuspendedTime) {
root.lastSuspendedTime = expirationTime + 1;
}
// This is a pending level. Check if it's higher priority than the next
// known pending level.
if (expirationTime > root.nextKnownPendingLevel) {
root.nextKnownPendingLevel = expirationTime;
}
}
}
export function markRootFinishedAtTime(
root: FiberRoot,
finishedExpirationTime: ExpirationTime,
remainingExpirationTime: ExpirationTime,
): void {
// Update the range of pending times
root.firstPendingTime = remainingExpirationTime;
if (remainingExpirationTime < root.lastPendingTime) {
// This usually means we've finished all the work, but it can also happen
// when something gets downprioritized during render, like a hidden tree.
root.lastPendingTime = remainingExpirationTime;
}
// Update the range of suspended times. Treat everything higher priority or
// equal to this update as unsuspended.
if (finishedExpirationTime <= root.lastSuspendedTime) {
// The entire suspended range is now unsuspended.
root.firstSuspendedTime = root.lastSuspendedTime = root.nextKnownPendingLevel = NoWork;
} else if (finishedExpirationTime <= root.firstSuspendedTime) {
// Part of the suspended range is now unsuspended. Narrow the range to
// include everything between the unsuspended time (non-inclusive) and the
// last suspended time.
root.firstSuspendedTime = finishedExpirationTime - 1;
}
if (finishedExpirationTime <= root.lastPingedTime) {
// Clear the pinged time
root.lastPingedTime = NoWork;
}
if (finishedExpirationTime <= root.lastExpiredTime) {
// Clear the expired time
root.lastExpiredTime = NoWork;
}
// Clear any pending updates that were just processed.
clearPendingMutableSourceUpdates(root, finishedExpirationTime);
}
export function markRootExpiredAtTime(
root: FiberRoot,
expirationTime: ExpirationTime,
): void {
const lastExpiredTime = root.lastExpiredTime;
if (lastExpiredTime === NoWork || lastExpiredTime > expirationTime) {
root.lastExpiredTime = expirationTime;
}
}