import type {ReactNodeList, ReactFormState} from 'shared/ReactTypes';
import type {
FiberRoot,
SuspenseHydrationCallbacks,
TransitionTracingCallbacks,
} from './ReactInternalTypes';
import type {RootTag} from './ReactRootTags';
import type {Cache} from './ReactFiberCacheComponent';
import type {Container} from './ReactFiberConfig';
import {noTimeout} from './ReactFiberConfig';
import {createHostRootFiber} from './ReactFiber';
import {
NoLane,
NoLanes,
NoTimestamp,
TotalLanes,
createLaneMap,
} from './ReactFiberLane';
import {
enableSuspenseCallback,
enableProfilerCommitHooks,
enableProfilerTimer,
enableUpdaterTracking,
enableTransitionTracing,
disableLegacyMode,
enableViewTransition,
enableGestureTransition,
enableDefaultTransitionIndicator,
} from 'shared/ReactFeatureFlags';
import {initializeUpdateQueue} from './ReactFiberClassUpdateQueue';
import {LegacyRoot, ConcurrentRoot} from './ReactRootTags';
import {createCache, retainCache} from './ReactFiberCacheComponent';
export type RootState = {
element: any,
isDehydrated: boolean,
cache: Cache,
};
function FiberRootNode(
this: $FlowFixMe,
containerInfo: any,
tag,
hydrate: any,
identifierPrefix: any,
onUncaughtError: any,
onCaughtError: any,
onRecoverableError: any,
onDefaultTransitionIndicator: any,
formState: ReactFormState<any, any> | null,
) {
this.tag = disableLegacyMode ? ConcurrentRoot : tag;
this.containerInfo = containerInfo;
this.pendingChildren = null;
this.current = null;
this.pingCache = null;
this.timeoutHandle = noTimeout;
this.cancelPendingCommit = null;
this.context = null;
this.pendingContext = null;
this.next = null;
this.callbackNode = null;
this.callbackPriority = NoLane;
this.expirationTimes = createLaneMap(NoTimestamp);
this.pendingLanes = NoLanes;
this.suspendedLanes = NoLanes;
this.pingedLanes = NoLanes;
this.warmLanes = NoLanes;
this.expiredLanes = NoLanes;
if (enableDefaultTransitionIndicator) {
this.indicatorLanes = NoLanes;
}
this.errorRecoveryDisabledLanes = NoLanes;
this.shellSuspendCounter = 0;
this.entangledLanes = NoLanes;
this.entanglements = createLaneMap(NoLanes);
this.hiddenUpdates = createLaneMap(null);
this.identifierPrefix = identifierPrefix;
this.onUncaughtError = onUncaughtError;
this.onCaughtError = onCaughtError;
this.onRecoverableError = onRecoverableError;
if (enableDefaultTransitionIndicator) {
this.onDefaultTransitionIndicator = onDefaultTransitionIndicator;
this.pendingIndicator = null;
}
this.pooledCache = null;
this.pooledCacheLanes = NoLanes;
if (enableSuspenseCallback) {
this.hydrationCallbacks = null;
}
this.formState = formState;
if (enableViewTransition) {
this.transitionTypes = null;
}
if (enableGestureTransition) {
this.pendingGestures = null;
this.stoppingGestures = null;
this.gestureClone = null;
}
this.incompleteTransitions = new Map();
if (enableTransitionTracing) {
this.transitionCallbacks = null;
this.transitionLanes = createLaneMap(null);
}
if (enableProfilerTimer && enableProfilerCommitHooks) {
this.effectDuration = -0;
this.passiveEffectDuration = -0;
}
if (enableUpdaterTracking) {
this.memoizedUpdaters = new Set();
const pendingUpdatersLaneMap = (this.pendingUpdatersLaneMap = []);
for (let i = 0; i < TotalLanes; i++) {
pendingUpdatersLaneMap.push(new Set());
}
}
if (__DEV__) {
if (disableLegacyMode) {
this._debugRootType = hydrate ? 'hydrateRoot()' : 'createRoot()';
} else {
switch (tag) {
case ConcurrentRoot:
this._debugRootType = hydrate ? 'hydrateRoot()' : 'createRoot()';
break;
case LegacyRoot:
this._debugRootType = hydrate ? 'hydrate()' : 'render()';
break;
}
}
}
}
export function createFiberRoot(
containerInfo: Container,
tag: RootTag,
hydrate: boolean,
initialChildren: ReactNodeList,
hydrationCallbacks: null | SuspenseHydrationCallbacks,
isStrictMode: boolean,
identifierPrefix: string,
formState: ReactFormState<any, any> | null,
onUncaughtError: (
error: mixed,
errorInfo: {+componentStack?: ?string},
) => void,
onCaughtError: (
error: mixed,
errorInfo: {
+componentStack?: ?string,
+errorBoundary?: ?React$Component<any, any>,
},
) => void,
onRecoverableError: (
error: mixed,
errorInfo: {+componentStack?: ?string},
) => void,
onDefaultTransitionIndicator: () => void | (() => void),
transitionCallbacks: null | TransitionTracingCallbacks,
): FiberRoot {
const root: FiberRoot = (new FiberRootNode(
containerInfo,
tag,
hydrate,
identifierPrefix,
onUncaughtError,
onCaughtError,
onRecoverableError,
onDefaultTransitionIndicator,
formState,
): any);
if (enableSuspenseCallback) {
root.hydrationCallbacks = hydrationCallbacks;
}
if (enableTransitionTracing) {
root.transitionCallbacks = transitionCallbacks;
}
const uninitializedFiber = createHostRootFiber(tag, isStrictMode);
root.current = uninitializedFiber;
uninitializedFiber.stateNode = root;
const initialCache = createCache();
retainCache(initialCache);
root.pooledCache = initialCache;
retainCache(initialCache);
const initialState: RootState = {
element: initialChildren,
isDehydrated: hydrate,
cache: initialCache,
};
uninitializedFiber.memoizedState = initialState;
initializeUpdateQueue(uninitializedFiber);
return root;
}