|
|
|
@ -15,21 +15,18 @@ import type {Interaction} from 'scheduler/src/Tracing';
|
|
|
|
|
import type {SuspenseState} from './ReactFiberSuspenseComponent.new';
|
|
|
|
|
import type {StackCursor} from './ReactFiberStack.new';
|
|
|
|
|
import type {FunctionComponentUpdateQueue} from './ReactFiberHooks.new';
|
|
|
|
|
import type {Flags} from './ReactFiberFlags';
|
|
|
|
|
|
|
|
|
|
import {
|
|
|
|
|
warnAboutDeprecatedLifecycles,
|
|
|
|
|
enableSuspenseServerRenderer,
|
|
|
|
|
replayFailedUnitOfWorkWithInvokeGuardedCallback,
|
|
|
|
|
enableProfilerTimer,
|
|
|
|
|
enableProfilerCommitHooks,
|
|
|
|
|
enableSchedulerTracing,
|
|
|
|
|
warnAboutUnmockedScheduler,
|
|
|
|
|
deferRenderPhaseUpdateToNextBatch,
|
|
|
|
|
decoupleUpdatePriorityFromScheduler,
|
|
|
|
|
enableDebugTracing,
|
|
|
|
|
enableSchedulingProfiler,
|
|
|
|
|
enableScopeAPI,
|
|
|
|
|
skipUnmountedBoundaries,
|
|
|
|
|
enableDoubleInvokingEffects,
|
|
|
|
|
} from 'shared/ReactFeatureFlags';
|
|
|
|
@ -83,13 +80,11 @@ import * as Scheduler from 'scheduler';
|
|
|
|
|
import {__interactionsRef, __subscriberRef} from 'scheduler/tracing';
|
|
|
|
|
|
|
|
|
|
import {
|
|
|
|
|
prepareForCommit,
|
|
|
|
|
resetAfterCommit,
|
|
|
|
|
scheduleTimeout,
|
|
|
|
|
cancelTimeout,
|
|
|
|
|
noTimeout,
|
|
|
|
|
warnsIfNotActing,
|
|
|
|
|
beforeActiveInstanceBlur,
|
|
|
|
|
afterActiveInstanceBlur,
|
|
|
|
|
clearContainer,
|
|
|
|
|
} from './ReactFiberHostConfig';
|
|
|
|
@ -116,31 +111,19 @@ import {
|
|
|
|
|
MemoComponent,
|
|
|
|
|
SimpleMemoComponent,
|
|
|
|
|
Block,
|
|
|
|
|
ScopeComponent,
|
|
|
|
|
Profiler,
|
|
|
|
|
} from './ReactWorkTags';
|
|
|
|
|
import {LegacyRoot} from './ReactRootTags';
|
|
|
|
|
import {
|
|
|
|
|
NoFlags,
|
|
|
|
|
Placement,
|
|
|
|
|
Update,
|
|
|
|
|
PlacementAndUpdate,
|
|
|
|
|
Ref,
|
|
|
|
|
ContentReset,
|
|
|
|
|
Snapshot,
|
|
|
|
|
Passive,
|
|
|
|
|
PassiveStatic,
|
|
|
|
|
Incomplete,
|
|
|
|
|
HostEffectMask,
|
|
|
|
|
Hydrating,
|
|
|
|
|
HydratingAndUpdate,
|
|
|
|
|
Visibility,
|
|
|
|
|
BeforeMutationMask,
|
|
|
|
|
MutationMask,
|
|
|
|
|
LayoutMask,
|
|
|
|
|
PassiveMask,
|
|
|
|
|
MountPassiveDev,
|
|
|
|
|
MountLayoutDev,
|
|
|
|
|
} from './ReactFiberFlags';
|
|
|
|
|
import {
|
|
|
|
|
NoLanePriority,
|
|
|
|
@ -191,22 +174,12 @@ import {
|
|
|
|
|
createClassErrorUpdate,
|
|
|
|
|
} from './ReactFiberThrow.new';
|
|
|
|
|
import {
|
|
|
|
|
commitBeforeMutationLifeCycles as commitBeforeMutationEffectOnFiber,
|
|
|
|
|
commitPlacement,
|
|
|
|
|
commitWork,
|
|
|
|
|
commitDeletion,
|
|
|
|
|
commitPassiveUnmount as commitPassiveUnmountOnFiber,
|
|
|
|
|
commitPassiveUnmountInsideDeletedTree as commitPassiveUnmountInsideDeletedTreeOnFiber,
|
|
|
|
|
commitPassiveMount as commitPassiveMountOnFiber,
|
|
|
|
|
commitDetachRef,
|
|
|
|
|
commitAttachRef,
|
|
|
|
|
commitResetTextContent,
|
|
|
|
|
isSuspenseBoundaryBeingHidden,
|
|
|
|
|
invokeLayoutEffectMountInDEV,
|
|
|
|
|
invokePassiveEffectMountInDEV,
|
|
|
|
|
invokeLayoutEffectUnmountInDEV,
|
|
|
|
|
invokePassiveEffectUnmountInDEV,
|
|
|
|
|
recursivelyCommitLayoutEffects,
|
|
|
|
|
commitBeforeMutationEffects,
|
|
|
|
|
commitMutationEffects,
|
|
|
|
|
commitLayoutEffects,
|
|
|
|
|
commitPassiveMountEffects,
|
|
|
|
|
commitPassiveUnmountEffects,
|
|
|
|
|
commitDoubleInvokeEffectsInDEV,
|
|
|
|
|
} from './ReactFiberCommitWork.new';
|
|
|
|
|
import {enqueueUpdate} from './ReactUpdateQueue.new';
|
|
|
|
|
import {resetContextDependencies} from './ReactFiberNewContext.new';
|
|
|
|
@ -247,7 +220,6 @@ import {onCommitRoot as onCommitRootTestSelector} from './ReactTestSelectors';
|
|
|
|
|
|
|
|
|
|
// Used by `act`
|
|
|
|
|
import enqueueTask from 'shared/enqueueTask';
|
|
|
|
|
import {doesFiberContain} from './ReactFiberTreeReflection';
|
|
|
|
|
|
|
|
|
|
const ceil = Math.ceil;
|
|
|
|
|
|
|
|
|
@ -327,9 +299,6 @@ let workInProgressRootRenderTargetTime: number = Infinity;
|
|
|
|
|
// suspense heuristics and opt out of rendering more content.
|
|
|
|
|
const RENDER_TIMEOUT_MS = 500;
|
|
|
|
|
|
|
|
|
|
// Used to avoid traversing the return path to find the nearest Profiler ancestor during commit.
|
|
|
|
|
let nearestProfilerOnStack: Fiber | null = null;
|
|
|
|
|
|
|
|
|
|
function resetRenderTimer() {
|
|
|
|
|
workInProgressRootRenderTargetTime = now() + RENDER_TIMEOUT_MS;
|
|
|
|
|
}
|
|
|
|
@ -374,9 +343,6 @@ let currentEventPendingLanes: Lanes = NoLanes;
|
|
|
|
|
// We warn about state updates for unmounted components differently in this case.
|
|
|
|
|
let isFlushingPassiveEffects = false;
|
|
|
|
|
|
|
|
|
|
let focusedInstanceHandle: null | Fiber = null;
|
|
|
|
|
let shouldFireAfterActiveInstanceBlur: boolean = false;
|
|
|
|
|
|
|
|
|
|
export function getWorkInProgressRoot(): FiberRoot | null {
|
|
|
|
|
return workInProgressRoot;
|
|
|
|
|
}
|
|
|
|
@ -1916,13 +1882,10 @@ function commitRootImpl(root, renderPriorityLevel) {
|
|
|
|
|
// The first phase a "before mutation" phase. We use this phase to read the
|
|
|
|
|
// state of the host tree right before we mutate it. This is where
|
|
|
|
|
// getSnapshotBeforeUpdate is called.
|
|
|
|
|
focusedInstanceHandle = prepareForCommit(root.containerInfo);
|
|
|
|
|
shouldFireAfterActiveInstanceBlur = false;
|
|
|
|
|
|
|
|
|
|
commitBeforeMutationEffects(finishedWork);
|
|
|
|
|
|
|
|
|
|
// We no longer need to track the active instance fiber
|
|
|
|
|
focusedInstanceHandle = null;
|
|
|
|
|
const shouldFireAfterActiveInstanceBlur = commitBeforeMutationEffects(
|
|
|
|
|
root,
|
|
|
|
|
finishedWork,
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
if (enableProfilerTimer) {
|
|
|
|
|
// Mark the current commit time to be shared by all Profilers in this
|
|
|
|
@ -1957,27 +1920,7 @@ function commitRootImpl(root, renderPriorityLevel) {
|
|
|
|
|
markLayoutEffectsStarted(lanes);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (__DEV__) {
|
|
|
|
|
setCurrentDebugFiberInDEV(finishedWork);
|
|
|
|
|
invokeGuardedCallback(
|
|
|
|
|
null,
|
|
|
|
|
recursivelyCommitLayoutEffects,
|
|
|
|
|
null,
|
|
|
|
|
finishedWork,
|
|
|
|
|
root,
|
|
|
|
|
);
|
|
|
|
|
if (hasCaughtError()) {
|
|
|
|
|
const error = clearCaughtError();
|
|
|
|
|
captureCommitPhaseErrorOnRoot(finishedWork, finishedWork, error);
|
|
|
|
|
}
|
|
|
|
|
resetCurrentDebugFiberInDEV();
|
|
|
|
|
} else {
|
|
|
|
|
try {
|
|
|
|
|
recursivelyCommitLayoutEffects(finishedWork, root);
|
|
|
|
|
} catch (error) {
|
|
|
|
|
captureCommitPhaseErrorOnRoot(finishedWork, finishedWork, error);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
commitLayoutEffects(finishedWork, root);
|
|
|
|
|
|
|
|
|
|
if (__DEV__) {
|
|
|
|
|
if (enableDebugTracing) {
|
|
|
|
@ -2117,238 +2060,6 @@ function commitRootImpl(root, renderPriorityLevel) {
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function commitBeforeMutationEffects(firstChild: Fiber) {
|
|
|
|
|
let fiber = firstChild;
|
|
|
|
|
while (fiber !== null) {
|
|
|
|
|
if (fiber.deletions !== null) {
|
|
|
|
|
commitBeforeMutationEffectsDeletions(fiber.deletions);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (fiber.child !== null) {
|
|
|
|
|
const primarySubtreeFlags = fiber.subtreeFlags & BeforeMutationMask;
|
|
|
|
|
if (primarySubtreeFlags !== NoFlags) {
|
|
|
|
|
commitBeforeMutationEffects(fiber.child);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (__DEV__) {
|
|
|
|
|
setCurrentDebugFiberInDEV(fiber);
|
|
|
|
|
invokeGuardedCallback(null, commitBeforeMutationEffectsImpl, null, fiber);
|
|
|
|
|
if (hasCaughtError()) {
|
|
|
|
|
const error = clearCaughtError();
|
|
|
|
|
captureCommitPhaseError(fiber, fiber.return, error);
|
|
|
|
|
}
|
|
|
|
|
resetCurrentDebugFiberInDEV();
|
|
|
|
|
} else {
|
|
|
|
|
try {
|
|
|
|
|
commitBeforeMutationEffectsImpl(fiber);
|
|
|
|
|
} catch (error) {
|
|
|
|
|
captureCommitPhaseError(fiber, fiber.return, error);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
fiber = fiber.sibling;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function commitBeforeMutationEffectsImpl(fiber: Fiber) {
|
|
|
|
|
const current = fiber.alternate;
|
|
|
|
|
const flags = fiber.flags;
|
|
|
|
|
|
|
|
|
|
if (!shouldFireAfterActiveInstanceBlur && focusedInstanceHandle !== null) {
|
|
|
|
|
// Check to see if the focused element was inside of a hidden (Suspense) subtree.
|
|
|
|
|
if (
|
|
|
|
|
// TODO: Can optimize this further with separate Hide and Show flags. We
|
|
|
|
|
// only care about Hide here.
|
|
|
|
|
(flags & Visibility) !== NoFlags &&
|
|
|
|
|
fiber.tag === SuspenseComponent &&
|
|
|
|
|
isSuspenseBoundaryBeingHidden(current, fiber) &&
|
|
|
|
|
doesFiberContain(fiber, focusedInstanceHandle)
|
|
|
|
|
) {
|
|
|
|
|
shouldFireAfterActiveInstanceBlur = true;
|
|
|
|
|
beforeActiveInstanceBlur(fiber);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ((flags & Snapshot) !== NoFlags) {
|
|
|
|
|
setCurrentDebugFiberInDEV(fiber);
|
|
|
|
|
commitBeforeMutationEffectOnFiber(current, fiber);
|
|
|
|
|
resetCurrentDebugFiberInDEV();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function commitBeforeMutationEffectsDeletions(deletions: Array<Fiber>) {
|
|
|
|
|
for (let i = 0; i < deletions.length; i++) {
|
|
|
|
|
const fiber = deletions[i];
|
|
|
|
|
|
|
|
|
|
// TODO (effects) It would be nice to avoid calling doesFiberContain()
|
|
|
|
|
// Maybe we can repurpose one of the subtreeFlags positions for this instead?
|
|
|
|
|
// Use it to store which part of the tree the focused instance is in?
|
|
|
|
|
// This assumes we can safely determine that instance during the "render" phase.
|
|
|
|
|
|
|
|
|
|
if (doesFiberContain(fiber, ((focusedInstanceHandle: any): Fiber))) {
|
|
|
|
|
shouldFireAfterActiveInstanceBlur = true;
|
|
|
|
|
beforeActiveInstanceBlur(fiber);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function commitMutationEffects(
|
|
|
|
|
firstChild: Fiber,
|
|
|
|
|
root: FiberRoot,
|
|
|
|
|
renderPriorityLevel: ReactPriorityLevel,
|
|
|
|
|
) {
|
|
|
|
|
let fiber = firstChild;
|
|
|
|
|
while (fiber !== null) {
|
|
|
|
|
const deletions = fiber.deletions;
|
|
|
|
|
if (deletions !== null) {
|
|
|
|
|
commitMutationEffectsDeletions(
|
|
|
|
|
deletions,
|
|
|
|
|
fiber,
|
|
|
|
|
root,
|
|
|
|
|
renderPriorityLevel,
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (fiber.child !== null) {
|
|
|
|
|
const mutationFlags = fiber.subtreeFlags & MutationMask;
|
|
|
|
|
if (mutationFlags !== NoFlags) {
|
|
|
|
|
commitMutationEffects(fiber.child, root, renderPriorityLevel);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (__DEV__) {
|
|
|
|
|
setCurrentDebugFiberInDEV(fiber);
|
|
|
|
|
invokeGuardedCallback(
|
|
|
|
|
null,
|
|
|
|
|
commitMutationEffectsImpl,
|
|
|
|
|
null,
|
|
|
|
|
fiber,
|
|
|
|
|
root,
|
|
|
|
|
renderPriorityLevel,
|
|
|
|
|
);
|
|
|
|
|
if (hasCaughtError()) {
|
|
|
|
|
const error = clearCaughtError();
|
|
|
|
|
captureCommitPhaseError(fiber, fiber.return, error);
|
|
|
|
|
}
|
|
|
|
|
resetCurrentDebugFiberInDEV();
|
|
|
|
|
} else {
|
|
|
|
|
try {
|
|
|
|
|
commitMutationEffectsImpl(fiber, root, renderPriorityLevel);
|
|
|
|
|
} catch (error) {
|
|
|
|
|
captureCommitPhaseError(fiber, fiber.return, error);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
fiber = fiber.sibling;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function commitMutationEffectsImpl(
|
|
|
|
|
fiber: Fiber,
|
|
|
|
|
root: FiberRoot,
|
|
|
|
|
renderPriorityLevel,
|
|
|
|
|
) {
|
|
|
|
|
const flags = fiber.flags;
|
|
|
|
|
if (flags & ContentReset) {
|
|
|
|
|
commitResetTextContent(fiber);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (flags & Ref) {
|
|
|
|
|
const current = fiber.alternate;
|
|
|
|
|
if (current !== null) {
|
|
|
|
|
commitDetachRef(current);
|
|
|
|
|
}
|
|
|
|
|
if (enableScopeAPI) {
|
|
|
|
|
// TODO: This is a temporary solution that allowed us to transition away from React Flare on www.
|
|
|
|
|
if (fiber.tag === ScopeComponent) {
|
|
|
|
|
commitAttachRef(fiber);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// The following switch statement is only concerned about placement,
|
|
|
|
|
// updates, and deletions. To avoid needing to add a case for every possible
|
|
|
|
|
// bitmap value, we remove the secondary effects from the effect tag and
|
|
|
|
|
// switch on that value.
|
|
|
|
|
const primaryFlags = flags & (Placement | Update | Hydrating);
|
|
|
|
|
switch (primaryFlags) {
|
|
|
|
|
case Placement: {
|
|
|
|
|
commitPlacement(fiber);
|
|
|
|
|
// Clear the "placement" from effect tag so that we know that this is
|
|
|
|
|
// inserted, before any life-cycles like componentDidMount gets called.
|
|
|
|
|
// TODO: findDOMNode doesn't rely on this any more but isMounted does
|
|
|
|
|
// and isMounted is deprecated anyway so we should be able to kill this.
|
|
|
|
|
fiber.flags &= ~Placement;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case PlacementAndUpdate: {
|
|
|
|
|
// Placement
|
|
|
|
|
commitPlacement(fiber);
|
|
|
|
|
// Clear the "placement" from effect tag so that we know that this is
|
|
|
|
|
// inserted, before any life-cycles like componentDidMount gets called.
|
|
|
|
|
fiber.flags &= ~Placement;
|
|
|
|
|
|
|
|
|
|
// Update
|
|
|
|
|
const current = fiber.alternate;
|
|
|
|
|
commitWork(current, fiber);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case Hydrating: {
|
|
|
|
|
fiber.flags &= ~Hydrating;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case HydratingAndUpdate: {
|
|
|
|
|
fiber.flags &= ~Hydrating;
|
|
|
|
|
|
|
|
|
|
// Update
|
|
|
|
|
const current = fiber.alternate;
|
|
|
|
|
commitWork(current, fiber);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case Update: {
|
|
|
|
|
const current = fiber.alternate;
|
|
|
|
|
commitWork(current, fiber);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function commitMutationEffectsDeletions(
|
|
|
|
|
deletions: Array<Fiber>,
|
|
|
|
|
nearestMountedAncestor: Fiber,
|
|
|
|
|
root: FiberRoot,
|
|
|
|
|
renderPriorityLevel,
|
|
|
|
|
) {
|
|
|
|
|
for (let i = 0; i < deletions.length; i++) {
|
|
|
|
|
const childToDelete = deletions[i];
|
|
|
|
|
if (__DEV__) {
|
|
|
|
|
invokeGuardedCallback(
|
|
|
|
|
null,
|
|
|
|
|
commitDeletion,
|
|
|
|
|
null,
|
|
|
|
|
root,
|
|
|
|
|
childToDelete,
|
|
|
|
|
nearestMountedAncestor,
|
|
|
|
|
renderPriorityLevel,
|
|
|
|
|
);
|
|
|
|
|
if (hasCaughtError()) {
|
|
|
|
|
const error = clearCaughtError();
|
|
|
|
|
captureCommitPhaseError(childToDelete, nearestMountedAncestor, error);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
try {
|
|
|
|
|
commitDeletion(
|
|
|
|
|
root,
|
|
|
|
|
childToDelete,
|
|
|
|
|
nearestMountedAncestor,
|
|
|
|
|
renderPriorityLevel,
|
|
|
|
|
);
|
|
|
|
|
} catch (error) {
|
|
|
|
|
captureCommitPhaseError(childToDelete, nearestMountedAncestor, error);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export function flushPassiveEffects(): boolean {
|
|
|
|
|
// Returns whether passive effects were flushed.
|
|
|
|
|
if (pendingPassiveEffectsRenderPriority !== NoSchedulerPriority) {
|
|
|
|
@ -2374,130 +2085,6 @@ export function flushPassiveEffects(): boolean {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function flushPassiveMountEffects(root, firstChild: Fiber): void {
|
|
|
|
|
let fiber = firstChild;
|
|
|
|
|
while (fiber !== null) {
|
|
|
|
|
let prevProfilerOnStack = null;
|
|
|
|
|
if (enableProfilerTimer && enableProfilerCommitHooks) {
|
|
|
|
|
if (fiber.tag === Profiler) {
|
|
|
|
|
prevProfilerOnStack = nearestProfilerOnStack;
|
|
|
|
|
nearestProfilerOnStack = fiber;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const primarySubtreeFlags = fiber.subtreeFlags & PassiveMask;
|
|
|
|
|
|
|
|
|
|
if (fiber.child !== null && primarySubtreeFlags !== NoFlags) {
|
|
|
|
|
flushPassiveMountEffects(root, fiber.child);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ((fiber.flags & Passive) !== NoFlags) {
|
|
|
|
|
if (__DEV__) {
|
|
|
|
|
setCurrentDebugFiberInDEV(fiber);
|
|
|
|
|
invokeGuardedCallback(
|
|
|
|
|
null,
|
|
|
|
|
commitPassiveMountOnFiber,
|
|
|
|
|
null,
|
|
|
|
|
root,
|
|
|
|
|
fiber,
|
|
|
|
|
);
|
|
|
|
|
if (hasCaughtError()) {
|
|
|
|
|
const error = clearCaughtError();
|
|
|
|
|
captureCommitPhaseError(fiber, fiber.return, error);
|
|
|
|
|
}
|
|
|
|
|
resetCurrentDebugFiberInDEV();
|
|
|
|
|
} else {
|
|
|
|
|
try {
|
|
|
|
|
commitPassiveMountOnFiber(root, fiber);
|
|
|
|
|
} catch (error) {
|
|
|
|
|
captureCommitPhaseError(fiber, fiber.return, error);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (enableProfilerTimer && enableProfilerCommitHooks) {
|
|
|
|
|
if (fiber.tag === Profiler) {
|
|
|
|
|
// Bubble times to the next nearest ancestor Profiler.
|
|
|
|
|
// After we process that Profiler, we'll bubble further up.
|
|
|
|
|
if (prevProfilerOnStack !== null) {
|
|
|
|
|
prevProfilerOnStack.stateNode.passiveEffectDuration +=
|
|
|
|
|
fiber.stateNode.passiveEffectDuration;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
nearestProfilerOnStack = prevProfilerOnStack;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fiber = fiber.sibling;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function flushPassiveUnmountEffects(firstChild: Fiber): void {
|
|
|
|
|
let fiber = firstChild;
|
|
|
|
|
while (fiber !== null) {
|
|
|
|
|
const deletions = fiber.deletions;
|
|
|
|
|
if (deletions !== null) {
|
|
|
|
|
for (let i = 0; i < deletions.length; i++) {
|
|
|
|
|
const fiberToDelete = deletions[i];
|
|
|
|
|
flushPassiveUnmountEffectsInsideOfDeletedTree(fiberToDelete, fiber);
|
|
|
|
|
|
|
|
|
|
// Now that passive effects have been processed, it's safe to detach lingering pointers.
|
|
|
|
|
detachFiberAfterEffects(fiberToDelete);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const child = fiber.child;
|
|
|
|
|
if (child !== null) {
|
|
|
|
|
// If any children have passive effects then traverse the subtree.
|
|
|
|
|
// Note that this requires checking subtreeFlags of the current Fiber,
|
|
|
|
|
// rather than the subtreeFlags/effectsTag of the first child,
|
|
|
|
|
// since that would not cover passive effects in siblings.
|
|
|
|
|
const passiveFlags = fiber.subtreeFlags & PassiveMask;
|
|
|
|
|
if (passiveFlags !== NoFlags) {
|
|
|
|
|
flushPassiveUnmountEffects(child);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const primaryFlags = fiber.flags & Passive;
|
|
|
|
|
if (primaryFlags !== NoFlags) {
|
|
|
|
|
setCurrentDebugFiberInDEV(fiber);
|
|
|
|
|
commitPassiveUnmountOnFiber(fiber);
|
|
|
|
|
resetCurrentDebugFiberInDEV();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fiber = fiber.sibling;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function flushPassiveUnmountEffectsInsideOfDeletedTree(
|
|
|
|
|
fiberToDelete: Fiber,
|
|
|
|
|
nearestMountedAncestor: Fiber,
|
|
|
|
|
): void {
|
|
|
|
|
if ((fiberToDelete.subtreeFlags & PassiveStatic) !== NoFlags) {
|
|
|
|
|
// If any children have passive effects then traverse the subtree.
|
|
|
|
|
// Note that this requires checking subtreeFlags of the current Fiber,
|
|
|
|
|
// rather than the subtreeFlags/effectsTag of the first child,
|
|
|
|
|
// since that would not cover passive effects in siblings.
|
|
|
|
|
let child = fiberToDelete.child;
|
|
|
|
|
while (child !== null) {
|
|
|
|
|
flushPassiveUnmountEffectsInsideOfDeletedTree(
|
|
|
|
|
child,
|
|
|
|
|
nearestMountedAncestor,
|
|
|
|
|
);
|
|
|
|
|
child = child.sibling;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ((fiberToDelete.flags & PassiveStatic) !== NoFlags) {
|
|
|
|
|
setCurrentDebugFiberInDEV(fiberToDelete);
|
|
|
|
|
commitPassiveUnmountInsideDeletedTreeOnFiber(
|
|
|
|
|
fiberToDelete,
|
|
|
|
|
nearestMountedAncestor,
|
|
|
|
|
);
|
|
|
|
|
resetCurrentDebugFiberInDEV();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function flushPassiveEffectsImpl() {
|
|
|
|
|
if (rootWithPendingPassiveEffects === null) {
|
|
|
|
|
return false;
|
|
|
|
@ -2537,8 +2124,8 @@ function flushPassiveEffectsImpl() {
|
|
|
|
|
// e.g. a destroy function in one component may unintentionally override a ref
|
|
|
|
|
// value set by a create function in another component.
|
|
|
|
|
// Layout effects have the same constraint.
|
|
|
|
|
flushPassiveUnmountEffects(root.current);
|
|
|
|
|
flushPassiveMountEffects(root, root.current);
|
|
|
|
|
commitPassiveUnmountEffects(root.current);
|
|
|
|
|
commitPassiveMountEffects(root, root.current);
|
|
|
|
|
|
|
|
|
|
if (__DEV__) {
|
|
|
|
|
if (enableDebugTracing) {
|
|
|
|
@ -2840,59 +2427,6 @@ function flushRenderPhaseStrictModeWarningsInDEV() {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function commitDoubleInvokeEffectsInDEV(
|
|
|
|
|
fiber: Fiber,
|
|
|
|
|
hasPassiveEffects: boolean,
|
|
|
|
|
) {
|
|
|
|
|
if (__DEV__ && enableDoubleInvokingEffects) {
|
|
|
|
|
// Never double-invoke effects for legacy roots.
|
|
|
|
|
if ((fiber.mode & (BlockingMode | ConcurrentMode)) === NoMode) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
setCurrentDebugFiberInDEV(fiber);
|
|
|
|
|
invokeEffectsInDev(fiber, MountLayoutDev, invokeLayoutEffectUnmountInDEV);
|
|
|
|
|
if (hasPassiveEffects) {
|
|
|
|
|
invokeEffectsInDev(
|
|
|
|
|
fiber,
|
|
|
|
|
MountPassiveDev,
|
|
|
|
|
invokePassiveEffectUnmountInDEV,
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
invokeEffectsInDev(fiber, MountLayoutDev, invokeLayoutEffectMountInDEV);
|
|
|
|
|
if (hasPassiveEffects) {
|
|
|
|
|
invokeEffectsInDev(fiber, MountPassiveDev, invokePassiveEffectMountInDEV);
|
|
|
|
|
}
|
|
|
|
|
resetCurrentDebugFiberInDEV();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function invokeEffectsInDev(
|
|
|
|
|
firstChild: Fiber,
|
|
|
|
|
fiberFlags: Flags,
|
|
|
|
|
invokeEffectFn: (fiber: Fiber) => void,
|
|
|
|
|
): void {
|
|
|
|
|
if (__DEV__ && enableDoubleInvokingEffects) {
|
|
|
|
|
// We don't need to re-check for legacy roots here.
|
|
|
|
|
// This function will not be called within legacy roots.
|
|
|
|
|
let fiber = firstChild;
|
|
|
|
|
while (fiber !== null) {
|
|
|
|
|
if (fiber.child !== null) {
|
|
|
|
|
const primarySubtreeFlag = fiber.subtreeFlags & fiberFlags;
|
|
|
|
|
if (primarySubtreeFlag !== NoFlags) {
|
|
|
|
|
invokeEffectsInDev(fiber.child, fiberFlags, invokeEffectFn);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ((fiber.flags & fiberFlags) !== NoFlags) {
|
|
|
|
|
invokeEffectFn(fiber);
|
|
|
|
|
}
|
|
|
|
|
fiber = fiber.sibling;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let didWarnStateUpdateForNotYetMountedComponent: Set<string> | null = null;
|
|
|
|
|
function warnAboutUpdateOnNotYetMountedFiberInDEV(fiber) {
|
|
|
|
|
if (__DEV__) {
|
|
|
|
@ -3675,21 +3209,3 @@ export function act(callback: () => Thenable<mixed>): Thenable<void> {
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function detachFiberAfterEffects(fiber: Fiber): void {
|
|
|
|
|
// Null out fields to improve GC for references that may be lingering (e.g. DevTools).
|
|
|
|
|
// Note that we already cleared the return pointer in detachFiberMutation().
|
|
|
|
|
fiber.child = null;
|
|
|
|
|
fiber.deletions = null;
|
|
|
|
|
fiber.dependencies = null;
|
|
|
|
|
fiber.memoizedProps = null;
|
|
|
|
|
fiber.memoizedState = null;
|
|
|
|
|
fiber.pendingProps = null;
|
|
|
|
|
fiber.sibling = null;
|
|
|
|
|
fiber.stateNode = null;
|
|
|
|
|
fiber.updateQueue = null;
|
|
|
|
|
|
|
|
|
|
if (__DEV__) {
|
|
|
|
|
fiber._debugOwner = null;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|