import type {Fiber, FiberRoot} from './ReactInternalTypes';
import type {RootState} from './ReactFiberRoot';
import type {Lanes, Lane} from './ReactFiberLane';
import type {
ReactScopeInstance,
ReactContext,
Wakeable,
} from 'shared/ReactTypes';
import type {
Instance,
Type,
Props,
Container,
ChildSet,
} from './ReactFiberHostConfig';
import type {
SuspenseState,
SuspenseListRenderState,
} from './ReactFiberSuspenseComponent';
import {isOffscreenManual} from './ReactFiberOffscreenComponent';
import type {OffscreenState} from './ReactFiberOffscreenComponent';
import type {TracingMarkerInstance} from './ReactFiberTracingMarkerComponent';
import type {Cache} from './ReactFiberCacheComponent';
import {
enableLegacyHidden,
enableHostSingletons,
enableSuspenseCallback,
enableScopeAPI,
enableProfilerTimer,
enableCache,
enableTransitionTracing,
enableFloat,
} from 'shared/ReactFeatureFlags';
import {resetWorkInProgressVersions as resetMutableSourceWorkInProgressVersions} from './ReactMutableSource';
import {now} from './Scheduler';
import {
IndeterminateComponent,
FunctionComponent,
ClassComponent,
HostRoot,
HostComponent,
HostResource,
HostSingleton,
HostText,
HostPortal,
ContextProvider,
ContextConsumer,
ForwardRef,
Fragment,
Mode,
Profiler,
SuspenseComponent,
SuspenseListComponent,
MemoComponent,
SimpleMemoComponent,
LazyComponent,
IncompleteClassComponent,
ScopeComponent,
OffscreenComponent,
LegacyHiddenComponent,
CacheComponent,
TracingMarkerComponent,
} from './ReactWorkTags';
import {NoMode, ConcurrentMode, ProfileMode} from './ReactTypeOfMode';
import {
Ref,
RefStatic,
Placement,
Update,
Visibility,
NoFlags,
DidCapture,
Snapshot,
ChildDeletion,
StaticMask,
MutationMask,
Passive,
Incomplete,
ShouldCapture,
ForceClientRender,
} from './ReactFiberFlags';
import {
createInstance,
createTextInstance,
resolveSingletonInstance,
appendInitialChild,
finalizeInitialChildren,
prepareUpdate,
supportsMutation,
supportsPersistence,
supportsResources,
supportsSingletons,
cloneInstance,
cloneHiddenInstance,
cloneHiddenTextInstance,
createContainerChildSet,
appendChildToContainerChildSet,
finalizeContainerChildren,
preparePortalMount,
prepareScopeUpdate,
} from './ReactFiberHostConfig';
import {
getRootHostContainer,
popHostContext,
getHostContext,
popHostContainer,
} from './ReactFiberHostContext';
import {
suspenseStackCursor,
popSuspenseListContext,
popSuspenseHandler,
pushSuspenseListContext,
setShallowSuspenseListContext,
ForceSuspenseFallback,
setDefaultShallowSuspenseListContext,
} from './ReactFiberSuspenseContext';
import {popHiddenContext} from './ReactFiberHiddenContext';
import {findFirstSuspended} from './ReactFiberSuspenseComponent';
import {
isContextProvider as isLegacyContextProvider,
popContext as popLegacyContext,
popTopLevelContextObject as popTopLevelLegacyContextObject,
} from './ReactFiberContext';
import {popProvider} from './ReactFiberNewContext';
import {
prepareToHydrateHostInstance,
prepareToHydrateHostTextInstance,
prepareToHydrateHostSuspenseInstance,
warnIfUnhydratedTailNodes,
popHydrationState,
resetHydrationState,
getIsHydrating,
hasUnhydratedTailNodes,
upgradeHydrationErrorsToRecoverable,
} from './ReactFiberHydrationContext';
import {
renderHasNotSuspendedYet,
getRenderTargetTime,
getWorkInProgressTransitions,
} from './ReactFiberWorkLoop';
import {
OffscreenLane,
SomeRetryLane,
NoLanes,
includesSomeLane,
mergeLanes,
} from './ReactFiberLane';
import {resetChildFibers} from './ReactChildFiber';
import {createScopeInstance} from './ReactFiberScope';
import {transferActualDuration} from './ReactProfilerTimer';
import {popCacheProvider} from './ReactFiberCacheComponent';
import {popTreeContext} from './ReactFiberTreeContext';
import {popRootTransition, popTransition} from './ReactFiberTransition';
import {
popMarkerInstance,
popRootMarkerInstance,
} from './ReactFiberTracingMarkerComponent';
function markUpdate(workInProgress: Fiber) {
workInProgress.flags |= Update;
}
function markRef(workInProgress: Fiber) {
workInProgress.flags |= Ref | RefStatic;
}
function hadNoMutationsEffects(current: null | Fiber, completedWork: Fiber) {
const didBailout = current !== null && current.child === completedWork.child;
if (didBailout) {
return true;
}
if ((completedWork.flags & ChildDeletion) !== NoFlags) {
return false;
}
let child = completedWork.child;
while (child !== null) {
if (
(child.flags & MutationMask) !== NoFlags ||
(child.subtreeFlags & MutationMask) !== NoFlags
) {
return false;
}
child = child.sibling;
}
return true;
}
let appendAllChildren;
let updateHostContainer;
let updateHostComponent;
let updateHostText;
if (supportsMutation) {
appendAllChildren = function(
parent: Instance,
workInProgress: Fiber,
needsVisibilityToggle: boolean,
isHidden: boolean,
) {
let node = workInProgress.child;
while (node !== null) {
if (node.tag === HostComponent || node.tag === HostText) {
appendInitialChild(parent, node.stateNode);
} else if (
node.tag === HostPortal ||
(enableHostSingletons && supportsSingletons
? node.tag === HostSingleton
: false)
) {
} else if (node.child !== null) {
node.child.return = node;
node = node.child;
continue;
}
if (node === workInProgress) {
return;
}
while (node.sibling === null) {
if (node.return === null || node.return === workInProgress) {
return;
}
node = node.return;
}
node.sibling.return = node.return;
node = node.sibling;
}
};
updateHostContainer = function(current: null | Fiber, workInProgress: Fiber) {
};
updateHostComponent = function(
current: Fiber,
workInProgress: Fiber,
type: Type,
newProps: Props,
) {
const oldProps = current.memoizedProps;
if (oldProps === newProps) {
return;
}
const instance: Instance = workInProgress.stateNode;
const currentHostContext = getHostContext();
const updatePayload = prepareUpdate(
instance,
type,
oldProps,
newProps,
currentHostContext,
);
workInProgress.updateQueue = (updatePayload: any);
if (updatePayload) {
markUpdate(workInProgress);
}
};
updateHostText = function(
current: Fiber,
workInProgress: Fiber,
oldText: string,
newText: string,
) {
if (oldText !== newText) {
markUpdate(workInProgress);
}
};
} else if (supportsPersistence) {
appendAllChildren = function(
parent: Instance,
workInProgress: Fiber,
needsVisibilityToggle: boolean,
isHidden: boolean,
) {
let node = workInProgress.child;
while (node !== null) {
branches: if (node.tag === HostComponent) {
let instance = node.stateNode;
if (needsVisibilityToggle && isHidden) {
const props = node.memoizedProps;
const type = node.type;
instance = cloneHiddenInstance(instance, type, props, node);
}
appendInitialChild(parent, instance);
} else if (node.tag === HostText) {
let instance = node.stateNode;
if (needsVisibilityToggle && isHidden) {
const text = node.memoizedProps;
instance = cloneHiddenTextInstance(instance, text, node);
}
appendInitialChild(parent, instance);
} else if (node.tag === HostPortal) {
} else if (
node.tag === OffscreenComponent &&
node.memoizedState !== null
) {
const child = node.child;
if (child !== null) {
child.return = node;
}
appendAllChildren(parent, node, true, true);
} else if (node.child !== null) {
node.child.return = node;
node = node.child;
continue;
}
node = (node: Fiber);
if (node === workInProgress) {
return;
}
while (node.sibling === null) {
if (node.return === null || node.return === workInProgress) {
return;
}
node = node.return;
}
node.sibling.return = node.return;
node = node.sibling;
}
};
const appendAllChildrenToContainer = function(
containerChildSet: ChildSet,
workInProgress: Fiber,
needsVisibilityToggle: boolean,
isHidden: boolean,
) {
let node = workInProgress.child;
while (node !== null) {
branches: if (node.tag === HostComponent) {
let instance = node.stateNode;
if (needsVisibilityToggle && isHidden) {
const props = node.memoizedProps;
const type = node.type;
instance = cloneHiddenInstance(instance, type, props, node);
}
appendChildToContainerChildSet(containerChildSet, instance);
} else if (node.tag === HostText) {
let instance = node.stateNode;
if (needsVisibilityToggle && isHidden) {
const text = node.memoizedProps;
instance = cloneHiddenTextInstance(instance, text, node);
}
appendChildToContainerChildSet(containerChildSet, instance);
} else if (node.tag === HostPortal) {
} else if (
node.tag === OffscreenComponent &&
node.memoizedState !== null
) {
const child = node.child;
if (child !== null) {
child.return = node;
}
const _needsVisibilityToggle = !isOffscreenManual(node);
appendAllChildrenToContainer(
containerChildSet,
node,
_needsVisibilityToggle,
true,
);
} else if (node.child !== null) {
node.child.return = node;
node = node.child;
continue;
}
node = (node: Fiber);
if (node === workInProgress) {
return;
}
while (node.sibling === null) {
if (node.return === null || node.return === workInProgress) {
return;
}
node = node.return;
}
node.sibling.return = node.return;
node = node.sibling;
}
};
updateHostContainer = function(current: null | Fiber, workInProgress: Fiber) {
const portalOrRoot: {
containerInfo: Container,
pendingChildren: ChildSet,
...
} = workInProgress.stateNode;
const childrenUnchanged = hadNoMutationsEffects(current, workInProgress);
if (childrenUnchanged) {
} else {
const container = portalOrRoot.containerInfo;
const newChildSet = createContainerChildSet(container);
appendAllChildrenToContainer(newChildSet, workInProgress, false, false);
portalOrRoot.pendingChildren = newChildSet;
markUpdate(workInProgress);
finalizeContainerChildren(container, newChildSet);
}
};
updateHostComponent = function(
current: Fiber,
workInProgress: Fiber,
type: Type,
newProps: Props,
) {
const currentInstance = current.stateNode;
const oldProps = current.memoizedProps;
const childrenUnchanged = hadNoMutationsEffects(current, workInProgress);
if (childrenUnchanged && oldProps === newProps) {
workInProgress.stateNode = currentInstance;
return;
}
const recyclableInstance: Instance = workInProgress.stateNode;
const currentHostContext = getHostContext();
let updatePayload = null;
if (oldProps !== newProps) {
updatePayload = prepareUpdate(
recyclableInstance,
type,
oldProps,
newProps,
currentHostContext,
);
}
if (childrenUnchanged && updatePayload === null) {
workInProgress.stateNode = currentInstance;
return;
}
const newInstance = cloneInstance(
currentInstance,
updatePayload,
type,
oldProps,
newProps,
workInProgress,
childrenUnchanged,
recyclableInstance,
);
if (
finalizeInitialChildren(newInstance, type, newProps, currentHostContext)
) {
markUpdate(workInProgress);
}
workInProgress.stateNode = newInstance;
if (childrenUnchanged) {
markUpdate(workInProgress);
} else {
appendAllChildren(newInstance, workInProgress, false, false);
}
};
updateHostText = function(
current: Fiber,
workInProgress: Fiber,
oldText: string,
newText: string,
) {
if (oldText !== newText) {
const rootContainerInstance = getRootHostContainer();
const currentHostContext = getHostContext();
workInProgress.stateNode = createTextInstance(
newText,
rootContainerInstance,
currentHostContext,
workInProgress,
);
markUpdate(workInProgress);
} else {
workInProgress.stateNode = current.stateNode;
}
};
} else {
updateHostContainer = function(current: null | Fiber, workInProgress: Fiber) {
};
updateHostComponent = function(
current: Fiber,
workInProgress: Fiber,
type: Type,
newProps: Props,
) {
};
updateHostText = function(
current: Fiber,
workInProgress: Fiber,
oldText: string,
newText: string,
) {
};
}
function cutOffTailIfNeeded(
renderState: SuspenseListRenderState,
hasRenderedATailFallback: boolean,
) {
if (getIsHydrating()) {
return;
}
switch (renderState.tailMode) {
case 'hidden': {
let tailNode = renderState.tail;
let lastTailNode = null;
while (tailNode !== null) {
if (tailNode.alternate !== null) {
lastTailNode = tailNode;
}
tailNode = tailNode.sibling;
}
if (lastTailNode === null) {
renderState.tail = null;
} else {
lastTailNode.sibling = null;
}
break;
}
case 'collapsed': {
let tailNode = renderState.tail;
let lastTailNode = null;
while (tailNode !== null) {
if (tailNode.alternate !== null) {
lastTailNode = tailNode;
}
tailNode = tailNode.sibling;
}
if (lastTailNode === null) {
if (!hasRenderedATailFallback && renderState.tail !== null) {
renderState.tail.sibling = null;
} else {
renderState.tail = null;
}
} else {
lastTailNode.sibling = null;
}
break;
}
}
}
function bubbleProperties(completedWork: Fiber) {
const didBailout =
completedWork.alternate !== null &&
completedWork.alternate.child === completedWork.child;
let newChildLanes = NoLanes;
let subtreeFlags = NoFlags;
if (!didBailout) {
if (enableProfilerTimer && (completedWork.mode & ProfileMode) !== NoMode) {
let actualDuration = completedWork.actualDuration;
let treeBaseDuration = ((completedWork.selfBaseDuration: any): number);
let child = completedWork.child;
while (child !== null) {
newChildLanes = mergeLanes(
newChildLanes,
mergeLanes(child.lanes, child.childLanes),
);
subtreeFlags |= child.subtreeFlags;
subtreeFlags |= child.flags;
actualDuration += child.actualDuration;
treeBaseDuration += child.treeBaseDuration;
child = child.sibling;
}
completedWork.actualDuration = actualDuration;
completedWork.treeBaseDuration = treeBaseDuration;
} else {
let child = completedWork.child;
while (child !== null) {
newChildLanes = mergeLanes(
newChildLanes,
mergeLanes(child.lanes, child.childLanes),
);
subtreeFlags |= child.subtreeFlags;
subtreeFlags |= child.flags;
child.return = completedWork;
child = child.sibling;
}
}
completedWork.subtreeFlags |= subtreeFlags;
} else {
if (enableProfilerTimer && (completedWork.mode & ProfileMode) !== NoMode) {
let treeBaseDuration = ((completedWork.selfBaseDuration: any): number);
let child = completedWork.child;
while (child !== null) {
newChildLanes = mergeLanes(
newChildLanes,
mergeLanes(child.lanes, child.childLanes),
);
subtreeFlags |= child.subtreeFlags & StaticMask;
subtreeFlags |= child.flags & StaticMask;
treeBaseDuration += child.treeBaseDuration;
child = child.sibling;
}
completedWork.treeBaseDuration = treeBaseDuration;
} else {
let child = completedWork.child;
while (child !== null) {
newChildLanes = mergeLanes(
newChildLanes,
mergeLanes(child.lanes, child.childLanes),
);
subtreeFlags |= child.subtreeFlags & StaticMask;
subtreeFlags |= child.flags & StaticMask;
child.return = completedWork;
child = child.sibling;
}
}
completedWork.subtreeFlags |= subtreeFlags;
}
completedWork.childLanes = newChildLanes;
return didBailout;
}
function completeDehydratedSuspenseBoundary(
current: Fiber | null,
workInProgress: Fiber,
nextState: SuspenseState | null,
): boolean {
if (
hasUnhydratedTailNodes() &&
(workInProgress.mode & ConcurrentMode) !== NoMode &&
(workInProgress.flags & DidCapture) === NoFlags
) {
warnIfUnhydratedTailNodes(workInProgress);
resetHydrationState();
workInProgress.flags |= ForceClientRender | Incomplete | ShouldCapture;
return false;
}
const wasHydrated = popHydrationState(workInProgress);
if (nextState !== null && nextState.dehydrated !== null) {
if (current === null) {
if (!wasHydrated) {
throw new Error(
'A dehydrated suspense component was completed without a hydrated node. ' +
'This is probably a bug in React.',
);
}
prepareToHydrateHostSuspenseInstance(workInProgress);
bubbleProperties(workInProgress);
if (enableProfilerTimer) {
if ((workInProgress.mode & ProfileMode) !== NoMode) {
const isTimedOutSuspense = nextState !== null;
if (isTimedOutSuspense) {
const primaryChildFragment = workInProgress.child;
if (primaryChildFragment !== null) {
workInProgress.treeBaseDuration -= ((primaryChildFragment.treeBaseDuration: any): number);
}
}
}
}
return false;
} else {
resetHydrationState();
if ((workInProgress.flags & DidCapture) === NoFlags) {
workInProgress.memoizedState = null;
}
workInProgress.flags |= Update;
bubbleProperties(workInProgress);
if (enableProfilerTimer) {
if ((workInProgress.mode & ProfileMode) !== NoMode) {
const isTimedOutSuspense = nextState !== null;
if (isTimedOutSuspense) {
const primaryChildFragment = workInProgress.child;
if (primaryChildFragment !== null) {
workInProgress.treeBaseDuration -= ((primaryChildFragment.treeBaseDuration: any): number);
}
}
}
}
return false;
}
} else {
upgradeHydrationErrorsToRecoverable();
return true;
}
}
function completeWork(
current: Fiber | null,
workInProgress: Fiber,
renderLanes: Lanes,
): Fiber | null {
const newProps = workInProgress.pendingProps;
popTreeContext(workInProgress);
switch (workInProgress.tag) {
case IndeterminateComponent:
case LazyComponent:
case SimpleMemoComponent:
case FunctionComponent:
case ForwardRef:
case Fragment:
case Mode:
case Profiler:
case ContextConsumer:
case MemoComponent:
bubbleProperties(workInProgress);
return null;
case ClassComponent: {
const Component = workInProgress.type;
if (isLegacyContextProvider(Component)) {
popLegacyContext(workInProgress);
}
bubbleProperties(workInProgress);
return null;
}
case HostRoot: {
const fiberRoot = (workInProgress.stateNode: FiberRoot);
if (enableTransitionTracing) {
const transitions = getWorkInProgressTransitions();
if (transitions !== null) {
workInProgress.flags |= Passive;
}
}
if (enableCache) {
let previousCache: Cache | null = null;
if (current !== null) {
previousCache = current.memoizedState.cache;
}
const cache: Cache = workInProgress.memoizedState.cache;
if (cache !== previousCache) {
workInProgress.flags |= Passive;
}
popCacheProvider(workInProgress, cache);
}
if (enableTransitionTracing) {
popRootMarkerInstance(workInProgress);
}
popRootTransition(workInProgress, fiberRoot, renderLanes);
popHostContainer(workInProgress);
popTopLevelLegacyContextObject(workInProgress);
resetMutableSourceWorkInProgressVersions();
if (fiberRoot.pendingContext) {
fiberRoot.context = fiberRoot.pendingContext;
fiberRoot.pendingContext = null;
}
if (current === null || current.child === null) {
const wasHydrated = popHydrationState(workInProgress);
if (wasHydrated) {
markUpdate(workInProgress);
} else {
if (current !== null) {
const prevState: RootState = current.memoizedState;
if (
!prevState.isDehydrated ||
(workInProgress.flags & ForceClientRender) !== NoFlags
) {
workInProgress.flags |= Snapshot;
upgradeHydrationErrorsToRecoverable();
}
}
}
}
updateHostContainer(current, workInProgress);
bubbleProperties(workInProgress);
if (enableTransitionTracing) {
if ((workInProgress.subtreeFlags & Visibility) !== NoFlags) {
workInProgress.flags |= Passive;
}
}
return null;
}
case HostResource: {
if (enableFloat && supportsResources) {
popHostContext(workInProgress);
const currentRef = current ? current.ref : null;
if (currentRef !== workInProgress.ref) {
markRef(workInProgress);
}
if (
current === null ||
current.memoizedState !== workInProgress.memoizedState
) {
markUpdate(workInProgress);
}
bubbleProperties(workInProgress);
return null;
}
}
case HostSingleton: {
if (enableHostSingletons && supportsSingletons) {
popHostContext(workInProgress);
const rootContainerInstance = getRootHostContainer();
const type = workInProgress.type;
if (current !== null && workInProgress.stateNode != null) {
updateHostComponent(current, workInProgress, type, newProps);
if (current.ref !== workInProgress.ref) {
markRef(workInProgress);
}
} else {
if (!newProps) {
if (workInProgress.stateNode === null) {
throw new Error(
'We must have new props for new mounts. This error is likely ' +
'caused by a bug in React. Please file an issue.',
);
}
bubbleProperties(workInProgress);
return null;
}
const currentHostContext = getHostContext();
const wasHydrated = popHydrationState(workInProgress);
if (wasHydrated) {
prepareToHydrateHostInstance(workInProgress, currentHostContext);
} else {
workInProgress.stateNode = resolveSingletonInstance(
type,
newProps,
rootContainerInstance,
currentHostContext,
true,
);
markUpdate(workInProgress);
}
if (workInProgress.ref !== null) {
markRef(workInProgress);
}
}
bubbleProperties(workInProgress);
return null;
}
}
case HostComponent: {
popHostContext(workInProgress);
const type = workInProgress.type;
if (current !== null && workInProgress.stateNode != null) {
updateHostComponent(current, workInProgress, type, newProps);
if (current.ref !== workInProgress.ref) {
markRef(workInProgress);
}
} else {
if (!newProps) {
if (workInProgress.stateNode === null) {
throw new Error(
'We must have new props for new mounts. This error is likely ' +
'caused by a bug in React. Please file an issue.',
);
}
bubbleProperties(workInProgress);
return null;
}
const currentHostContext = getHostContext();
const wasHydrated = popHydrationState(workInProgress);
if (wasHydrated) {
if (
prepareToHydrateHostInstance(workInProgress, currentHostContext)
) {
markUpdate(workInProgress);
}
} else {
const rootContainerInstance = getRootHostContainer();
const instance = createInstance(
type,
newProps,
rootContainerInstance,
currentHostContext,
workInProgress,
);
appendAllChildren(instance, workInProgress, false, false);
workInProgress.stateNode = instance;
if (
finalizeInitialChildren(
instance,
type,
newProps,
currentHostContext,
)
) {
markUpdate(workInProgress);
}
}
if (workInProgress.ref !== null) {
markRef(workInProgress);
}
}
bubbleProperties(workInProgress);
return null;
}
case HostText: {
const newText = newProps;
if (current && workInProgress.stateNode != null) {
const oldText = current.memoizedProps;
updateHostText(current, workInProgress, oldText, newText);
} else {
if (typeof newText !== 'string') {
if (workInProgress.stateNode === null) {
throw new Error(
'We must have new props for new mounts. This error is likely ' +
'caused by a bug in React. Please file an issue.',
);
}
}
const rootContainerInstance = getRootHostContainer();
const currentHostContext = getHostContext();
const wasHydrated = popHydrationState(workInProgress);
if (wasHydrated) {
if (prepareToHydrateHostTextInstance(workInProgress)) {
markUpdate(workInProgress);
}
} else {
workInProgress.stateNode = createTextInstance(
newText,
rootContainerInstance,
currentHostContext,
workInProgress,
);
}
}
bubbleProperties(workInProgress);
return null;
}
case SuspenseComponent: {
popSuspenseHandler(workInProgress);
const nextState: null | SuspenseState = workInProgress.memoizedState;
if (
current === null ||
(current.memoizedState !== null &&
current.memoizedState.dehydrated !== null)
) {
const fallthroughToNormalSuspensePath = completeDehydratedSuspenseBoundary(
current,
workInProgress,
nextState,
);
if (!fallthroughToNormalSuspensePath) {
if (workInProgress.flags & ShouldCapture) {
return workInProgress;
} else {
return null;
}
}
}
if ((workInProgress.flags & DidCapture) !== NoFlags) {
workInProgress.lanes = renderLanes;
if (
enableProfilerTimer &&
(workInProgress.mode & ProfileMode) !== NoMode
) {
transferActualDuration(workInProgress);
}
return workInProgress;
}
const nextDidTimeout = nextState !== null;
const prevDidTimeout =
current !== null &&
(current.memoizedState: null | SuspenseState) !== null;
if (enableCache && nextDidTimeout) {
const offscreenFiber: Fiber = (workInProgress.child: any);
let previousCache: Cache | null = null;
if (
offscreenFiber.alternate !== null &&
offscreenFiber.alternate.memoizedState !== null &&
offscreenFiber.alternate.memoizedState.cachePool !== null
) {
previousCache = offscreenFiber.alternate.memoizedState.cachePool.pool;
}
let cache: Cache | null = null;
if (
offscreenFiber.memoizedState !== null &&
offscreenFiber.memoizedState.cachePool !== null
) {
cache = offscreenFiber.memoizedState.cachePool.pool;
}
if (cache !== previousCache) {
offscreenFiber.flags |= Passive;
}
}
if (nextDidTimeout !== prevDidTimeout) {
if (enableTransitionTracing) {
const offscreenFiber: Fiber = (workInProgress.child: any);
offscreenFiber.flags |= Passive;
}
if (nextDidTimeout) {
const offscreenFiber: Fiber = (workInProgress.child: any);
offscreenFiber.flags |= Visibility;
}
}
const wakeables: Set<Wakeable> | null = (workInProgress.updateQueue: any);
if (wakeables !== null) {
workInProgress.flags |= Update;
}
if (
enableSuspenseCallback &&
workInProgress.updateQueue !== null &&
workInProgress.memoizedProps.suspenseCallback != null
) {
workInProgress.flags |= Update;
}
bubbleProperties(workInProgress);
if (enableProfilerTimer) {
if ((workInProgress.mode & ProfileMode) !== NoMode) {
if (nextDidTimeout) {
const primaryChildFragment = workInProgress.child;
if (primaryChildFragment !== null) {
workInProgress.treeBaseDuration -= ((primaryChildFragment.treeBaseDuration: any): number);
}
}
}
}
return null;
}
case HostPortal:
popHostContainer(workInProgress);
updateHostContainer(current, workInProgress);
if (current === null) {
preparePortalMount(workInProgress.stateNode.containerInfo);
}
bubbleProperties(workInProgress);
return null;
case ContextProvider:
const context: ReactContext<any> = workInProgress.type._context;
popProvider(context, workInProgress);
bubbleProperties(workInProgress);
return null;
case IncompleteClassComponent: {
const Component = workInProgress.type;
if (isLegacyContextProvider(Component)) {
popLegacyContext(workInProgress);
}
bubbleProperties(workInProgress);
return null;
}
case SuspenseListComponent: {
popSuspenseListContext(workInProgress);
const renderState: null | SuspenseListRenderState =
workInProgress.memoizedState;
if (renderState === null) {
bubbleProperties(workInProgress);
return null;
}
let didSuspendAlready = (workInProgress.flags & DidCapture) !== NoFlags;
const renderedTail = renderState.rendering;
if (renderedTail === null) {
if (!didSuspendAlready) {
const cannotBeSuspended =
renderHasNotSuspendedYet() &&
(current === null || (current.flags & DidCapture) === NoFlags);
if (!cannotBeSuspended) {
let row = workInProgress.child;
while (row !== null) {
const suspended = findFirstSuspended(row);
if (suspended !== null) {
didSuspendAlready = true;
workInProgress.flags |= DidCapture;
cutOffTailIfNeeded(renderState, false);
const newThenables = suspended.updateQueue;
if (newThenables !== null) {
workInProgress.updateQueue = newThenables;
workInProgress.flags |= Update;
}
workInProgress.subtreeFlags = NoFlags;
resetChildFibers(workInProgress, renderLanes);
pushSuspenseListContext(
workInProgress,
setShallowSuspenseListContext(
suspenseStackCursor.current,
ForceSuspenseFallback,
),
);
return workInProgress.child;
}
row = row.sibling;
}
}
if (renderState.tail !== null && now() > getRenderTargetTime()) {
workInProgress.flags |= DidCapture;
didSuspendAlready = true;
cutOffTailIfNeeded(renderState, false);
workInProgress.lanes = SomeRetryLane;
}
} else {
cutOffTailIfNeeded(renderState, false);
}
} else {
if (!didSuspendAlready) {
const suspended = findFirstSuspended(renderedTail);
if (suspended !== null) {
workInProgress.flags |= DidCapture;
didSuspendAlready = true;
const newThenables = suspended.updateQueue;
if (newThenables !== null) {
workInProgress.updateQueue = newThenables;
workInProgress.flags |= Update;
}
cutOffTailIfNeeded(renderState, true);
if (
renderState.tail === null &&
renderState.tailMode === 'hidden' &&
!renderedTail.alternate &&
!getIsHydrating()
) {
bubbleProperties(workInProgress);
return null;
}
} else if (
now() * 2 - renderState.renderingStartTime >
getRenderTargetTime() &&
renderLanes !== OffscreenLane
) {
workInProgress.flags |= DidCapture;
didSuspendAlready = true;
cutOffTailIfNeeded(renderState, false);
workInProgress.lanes = SomeRetryLane;
}
}
if (renderState.isBackwards) {
renderedTail.sibling = workInProgress.child;
workInProgress.child = renderedTail;
} else {
const previousSibling = renderState.last;
if (previousSibling !== null) {
previousSibling.sibling = renderedTail;
} else {
workInProgress.child = renderedTail;
}
renderState.last = renderedTail;
}
}
if (renderState.tail !== null) {
const next = renderState.tail;
renderState.rendering = next;
renderState.tail = next.sibling;
renderState.renderingStartTime = now();
next.sibling = null;
let suspenseContext = suspenseStackCursor.current;
if (didSuspendAlready) {
suspenseContext = setShallowSuspenseListContext(
suspenseContext,
ForceSuspenseFallback,
);
} else {
suspenseContext = setDefaultShallowSuspenseListContext(
suspenseContext,
);
}
pushSuspenseListContext(workInProgress, suspenseContext);
return next;
}
bubbleProperties(workInProgress);
return null;
}
case ScopeComponent: {
if (enableScopeAPI) {
if (current === null) {
const scopeInstance: ReactScopeInstance = createScopeInstance();
workInProgress.stateNode = scopeInstance;
prepareScopeUpdate(scopeInstance, workInProgress);
if (workInProgress.ref !== null) {
markRef(workInProgress);
markUpdate(workInProgress);
}
} else {
if (workInProgress.ref !== null) {
markUpdate(workInProgress);
}
if (current.ref !== workInProgress.ref) {
markRef(workInProgress);
}
}
bubbleProperties(workInProgress);
return null;
}
break;
}
case OffscreenComponent:
case LegacyHiddenComponent: {
popSuspenseHandler(workInProgress);
popHiddenContext(workInProgress);
const nextState: OffscreenState | null = workInProgress.memoizedState;
const nextIsHidden = nextState !== null;
if (enableLegacyHidden && workInProgress.tag === LegacyHiddenComponent) {
} else {
if (current !== null) {
const prevState: OffscreenState | null = current.memoizedState;
const prevIsHidden = prevState !== null;
if (prevIsHidden !== nextIsHidden) {
workInProgress.flags |= Visibility;
}
} else {
if (nextIsHidden) {
workInProgress.flags |= Visibility;
}
}
}
if (!nextIsHidden || (workInProgress.mode & ConcurrentMode) === NoMode) {
bubbleProperties(workInProgress);
} else {
if (
includesSomeLane(renderLanes, (OffscreenLane: Lane)) &&
(workInProgress.flags & DidCapture) === NoLanes
) {
bubbleProperties(workInProgress);
if (
(!enableLegacyHidden ||
workInProgress.tag !== LegacyHiddenComponent) &&
workInProgress.subtreeFlags & (Placement | Update)
) {
workInProgress.flags |= Visibility;
}
}
}
if (workInProgress.updateQueue !== null) {
workInProgress.flags |= Update;
}
if (enableCache) {
let previousCache: Cache | null = null;
if (
current !== null &&
current.memoizedState !== null &&
current.memoizedState.cachePool !== null
) {
previousCache = current.memoizedState.cachePool.pool;
}
let cache: Cache | null = null;
if (
workInProgress.memoizedState !== null &&
workInProgress.memoizedState.cachePool !== null
) {
cache = workInProgress.memoizedState.cachePool.pool;
}
if (cache !== previousCache) {
workInProgress.flags |= Passive;
}
}
popTransition(workInProgress, current);
return null;
}
case CacheComponent: {
if (enableCache) {
let previousCache: Cache | null = null;
if (current !== null) {
previousCache = current.memoizedState.cache;
}
const cache: Cache = workInProgress.memoizedState.cache;
if (cache !== previousCache) {
workInProgress.flags |= Passive;
}
popCacheProvider(workInProgress, cache);
bubbleProperties(workInProgress);
}
return null;
}
case TracingMarkerComponent: {
if (enableTransitionTracing) {
const instance: TracingMarkerInstance | null = workInProgress.stateNode;
if (instance !== null) {
popMarkerInstance(workInProgress);
}
bubbleProperties(workInProgress);
}
return null;
}
}
throw new Error(
`Unknown unit of work tag (${workInProgress.tag}). This error is likely caused by a bug in ` +
'React. Please file an issue.',
);
}
export {completeWork};