mirror of
https://github.com/facebook/react.git
synced 2025-11-01 09:12:30 +00:00
6de32a5a07
This update was a bit more involved. - `React$Component` was removed, I replaced it with Flow component types. - Flow removed shipping the standard library. This adds the environment libraries back from `flow-typed` which seemed to have changed slightly (probably got more precise and less `any`s). Suppresses some new type errors.
238 lines
6.7 KiB
JavaScript
238 lines
6.7 KiB
JavaScript
/**
|
|
* Copyright (c) Meta Platforms, Inc. and 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 {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,
|
|
// $FlowFixMe[missing-local-annot]
|
|
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) {
|
|
// TODO: This varies by each renderer.
|
|
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,
|
|
// TODO: We have several of these arguments that are conceptually part of the
|
|
// host config, but because they are passed in at runtime, we have to thread
|
|
// them through the root constructor. Perhaps we should put them all into a
|
|
// single type, like a DynamicHostConfig that is defined by the renderer.
|
|
identifierPrefix: string,
|
|
formState: ReactFormState<any, any> | null,
|
|
onUncaughtError: (
|
|
error: mixed,
|
|
errorInfo: {+componentStack?: ?string},
|
|
) => void,
|
|
onCaughtError: (
|
|
error: mixed,
|
|
errorInfo: {
|
|
+componentStack?: ?string,
|
|
+errorBoundary?: ?component(...props: any),
|
|
},
|
|
) => void,
|
|
onRecoverableError: (
|
|
error: mixed,
|
|
errorInfo: {+componentStack?: ?string},
|
|
) => void,
|
|
onDefaultTransitionIndicator: () => void | (() => void),
|
|
transitionCallbacks: null | TransitionTracingCallbacks,
|
|
): FiberRoot {
|
|
// $FlowFixMe[invalid-constructor] Flow no longer supports calling new on functions
|
|
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;
|
|
}
|
|
|
|
// Cyclic construction. This cheats the type system right now because
|
|
// stateNode is any.
|
|
const uninitializedFiber = createHostRootFiber(tag, isStrictMode);
|
|
root.current = uninitializedFiber;
|
|
uninitializedFiber.stateNode = root;
|
|
|
|
const initialCache = createCache();
|
|
retainCache(initialCache);
|
|
|
|
// The pooledCache is a fresh cache instance that is used temporarily
|
|
// for newly mounted boundaries during a render. In general, the
|
|
// pooledCache is always cleared from the root at the end of a render:
|
|
// it is either released when render commits, or moved to an Offscreen
|
|
// component if rendering suspends. Because the lifetime of the pooled
|
|
// cache is distinct from the main memoizedState.cache, it must be
|
|
// retained separately.
|
|
root.pooledCache = initialCache;
|
|
retainCache(initialCache);
|
|
const initialState: RootState = {
|
|
element: initialChildren,
|
|
isDehydrated: hydrate,
|
|
cache: initialCache,
|
|
};
|
|
uninitializedFiber.memoizedState = initialState;
|
|
|
|
initializeUpdateQueue(uninitializedFiber);
|
|
|
|
return root;
|
|
}
|