diff --git a/packages/react-reconciler/src/ReactFiberCommitWork.new.js b/packages/react-reconciler/src/ReactFiberCommitWork.new.js
index 32bb1028add82..4f77868463fc5 100644
--- a/packages/react-reconciler/src/ReactFiberCommitWork.new.js
+++ b/packages/react-reconciler/src/ReactFiberCommitWork.new.js
@@ -69,8 +69,11 @@ import {
ChildDeletion,
Snapshot,
Update,
+ Callback,
+ Ref,
Passive,
PassiveMask,
+ LayoutMask,
PassiveUnmountPendingDev,
} from './ReactFiberFlags';
import getComponentName from 'shared/getComponentName';
@@ -490,95 +493,154 @@ export function commitPassiveEffectDurations(
}
}
-function commitLifeCycles(
+function commitLayoutEffectOnFiber(
finishedRoot: FiberRoot,
current: Fiber | null,
finishedWork: Fiber,
committedLanes: Lanes,
): void {
- switch (finishedWork.tag) {
- case FunctionComponent:
- case ForwardRef:
- case SimpleMemoComponent: {
- // At this point layout effects have already been destroyed (during mutation phase).
- // This is done to prevent sibling component effects from interfering with each other,
- // e.g. a destroy function in one component should never override a ref set
- // by a create function in another component during the same commit.
- if (
- enableProfilerTimer &&
- enableProfilerCommitHooks &&
- finishedWork.mode & ProfileMode
- ) {
- try {
- startLayoutEffectTimer();
+ if ((finishedWork.flags & (Update | Callback)) !== NoFlags) {
+ switch (finishedWork.tag) {
+ case FunctionComponent:
+ case ForwardRef:
+ case SimpleMemoComponent: {
+ // At this point layout effects have already been destroyed (during mutation phase).
+ // This is done to prevent sibling component effects from interfering with each other,
+ // e.g. a destroy function in one component should never override a ref set
+ // by a create function in another component during the same commit.
+ if (
+ enableProfilerTimer &&
+ enableProfilerCommitHooks &&
+ finishedWork.mode & ProfileMode
+ ) {
+ try {
+ startLayoutEffectTimer();
+ commitHookEffectListMount(HookLayout | HookHasEffect, finishedWork);
+ } finally {
+ recordLayoutEffectDuration(finishedWork);
+ }
+ } else {
commitHookEffectListMount(HookLayout | HookHasEffect, finishedWork);
- } finally {
- recordLayoutEffectDuration(finishedWork);
}
- } else {
- commitHookEffectListMount(HookLayout | HookHasEffect, finishedWork);
- }
- schedulePassiveEffects(finishedWork);
- return;
- }
- case ClassComponent: {
- const instance = finishedWork.stateNode;
- if (finishedWork.flags & Update) {
- if (current === null) {
- // We could update instance props and state here,
- // but instead we rely on them being set during last render.
- // TODO: revisit this when we implement resuming.
- if (__DEV__) {
+ schedulePassiveEffects(finishedWork);
+ break;
+ }
+ case ClassComponent: {
+ const instance = finishedWork.stateNode;
+ if (finishedWork.flags & Update) {
+ if (current === null) {
+ // We could update instance props and state here,
+ // but instead we rely on them being set during last render.
+ // TODO: revisit this when we implement resuming.
+ if (__DEV__) {
+ if (
+ finishedWork.type === finishedWork.elementType &&
+ !didWarnAboutReassigningProps
+ ) {
+ if (instance.props !== finishedWork.memoizedProps) {
+ console.error(
+ 'Expected %s props to match memoized props before ' +
+ 'componentDidMount. ' +
+ 'This might either be because of a bug in React, or because ' +
+ 'a component reassigns its own `this.props`. ' +
+ 'Please file an issue.',
+ getComponentName(finishedWork.type) || 'instance',
+ );
+ }
+ if (instance.state !== finishedWork.memoizedState) {
+ console.error(
+ 'Expected %s state to match memoized state before ' +
+ 'componentDidMount. ' +
+ 'This might either be because of a bug in React, or because ' +
+ 'a component reassigns its own `this.state`. ' +
+ 'Please file an issue.',
+ getComponentName(finishedWork.type) || 'instance',
+ );
+ }
+ }
+ }
if (
- finishedWork.type === finishedWork.elementType &&
- !didWarnAboutReassigningProps
+ enableProfilerTimer &&
+ enableProfilerCommitHooks &&
+ finishedWork.mode & ProfileMode
) {
- if (instance.props !== finishedWork.memoizedProps) {
- console.error(
- 'Expected %s props to match memoized props before ' +
- 'componentDidMount. ' +
- 'This might either be because of a bug in React, or because ' +
- 'a component reassigns its own `this.props`. ' +
- 'Please file an issue.',
- getComponentName(finishedWork.type) || 'instance',
- );
+ try {
+ startLayoutEffectTimer();
+ instance.componentDidMount();
+ } finally {
+ recordLayoutEffectDuration(finishedWork);
}
- if (instance.state !== finishedWork.memoizedState) {
- console.error(
- 'Expected %s state to match memoized state before ' +
- 'componentDidMount. ' +
- 'This might either be because of a bug in React, or because ' +
- 'a component reassigns its own `this.state`. ' +
- 'Please file an issue.',
- getComponentName(finishedWork.type) || 'instance',
- );
- }
- }
- }
- if (
- enableProfilerTimer &&
- enableProfilerCommitHooks &&
- finishedWork.mode & ProfileMode
- ) {
- try {
- startLayoutEffectTimer();
+ } else {
instance.componentDidMount();
- } finally {
- recordLayoutEffectDuration(finishedWork);
}
} else {
- instance.componentDidMount();
+ const prevProps =
+ finishedWork.elementType === finishedWork.type
+ ? current.memoizedProps
+ : resolveDefaultProps(finishedWork.type, current.memoizedProps);
+ const prevState = current.memoizedState;
+ // We could update instance props and state here,
+ // but instead we rely on them being set during last render.
+ // TODO: revisit this when we implement resuming.
+ if (__DEV__) {
+ if (
+ finishedWork.type === finishedWork.elementType &&
+ !didWarnAboutReassigningProps
+ ) {
+ if (instance.props !== finishedWork.memoizedProps) {
+ console.error(
+ 'Expected %s props to match memoized props before ' +
+ 'componentDidUpdate. ' +
+ 'This might either be because of a bug in React, or because ' +
+ 'a component reassigns its own `this.props`. ' +
+ 'Please file an issue.',
+ getComponentName(finishedWork.type) || 'instance',
+ );
+ }
+ if (instance.state !== finishedWork.memoizedState) {
+ console.error(
+ 'Expected %s state to match memoized state before ' +
+ 'componentDidUpdate. ' +
+ 'This might either be because of a bug in React, or because ' +
+ 'a component reassigns its own `this.state`. ' +
+ 'Please file an issue.',
+ getComponentName(finishedWork.type) || 'instance',
+ );
+ }
+ }
+ }
+ if (
+ enableProfilerTimer &&
+ enableProfilerCommitHooks &&
+ finishedWork.mode & ProfileMode
+ ) {
+ try {
+ startLayoutEffectTimer();
+ instance.componentDidUpdate(
+ prevProps,
+ prevState,
+ instance.__reactInternalSnapshotBeforeUpdate,
+ );
+ } finally {
+ recordLayoutEffectDuration(finishedWork);
+ }
+ } else {
+ instance.componentDidUpdate(
+ prevProps,
+ prevState,
+ instance.__reactInternalSnapshotBeforeUpdate,
+ );
+ }
}
- } else {
- const prevProps =
- finishedWork.elementType === finishedWork.type
- ? current.memoizedProps
- : resolveDefaultProps(finishedWork.type, current.memoizedProps);
- const prevState = current.memoizedState;
- // We could update instance props and state here,
- // but instead we rely on them being set during last render.
- // TODO: revisit this when we implement resuming.
+ }
+
+ // TODO: I think this is now always non-null by the time it reaches the
+ // commit phase. Consider removing the type check.
+ const updateQueue: UpdateQueue<
+ *,
+ > | null = (finishedWork.updateQueue: any);
+ if (updateQueue !== null) {
if (__DEV__) {
if (
finishedWork.type === finishedWork.elementType &&
@@ -587,7 +649,7 @@ function commitLifeCycles(
if (instance.props !== finishedWork.memoizedProps) {
console.error(
'Expected %s props to match memoized props before ' +
- 'componentDidUpdate. ' +
+ 'processing the update queue. ' +
'This might either be because of a bug in React, or because ' +
'a component reassigns its own `this.props`. ' +
'Please file an issue.',
@@ -597,7 +659,7 @@ function commitLifeCycles(
if (instance.state !== finishedWork.memoizedState) {
console.error(
'Expected %s state to match memoized state before ' +
- 'componentDidUpdate. ' +
+ 'processing the update queue. ' +
'This might either be because of a bug in React, or because ' +
'a component reassigns its own `this.state`. ' +
'Please file an issue.',
@@ -606,210 +668,166 @@ function commitLifeCycles(
}
}
}
- if (
- enableProfilerTimer &&
- enableProfilerCommitHooks &&
- finishedWork.mode & ProfileMode
- ) {
- try {
- startLayoutEffectTimer();
- instance.componentDidUpdate(
- prevProps,
- prevState,
- instance.__reactInternalSnapshotBeforeUpdate,
- );
- } finally {
- recordLayoutEffectDuration(finishedWork);
- }
- } else {
- instance.componentDidUpdate(
- prevProps,
- prevState,
- instance.__reactInternalSnapshotBeforeUpdate,
- );
- }
+ // We could update instance props and state here,
+ // but instead we rely on them being set during last render.
+ // TODO: revisit this when we implement resuming.
+ commitUpdateQueue(finishedWork, updateQueue, instance);
}
+ break;
}
-
- // TODO: I think this is now always non-null by the time it reaches the
- // commit phase. Consider removing the type check.
- const updateQueue: UpdateQueue<
- *,
- > | null = (finishedWork.updateQueue: any);
- if (updateQueue !== null) {
- if (__DEV__) {
- if (
- finishedWork.type === finishedWork.elementType &&
- !didWarnAboutReassigningProps
- ) {
- if (instance.props !== finishedWork.memoizedProps) {
- console.error(
- 'Expected %s props to match memoized props before ' +
- 'processing the update queue. ' +
- 'This might either be because of a bug in React, or because ' +
- 'a component reassigns its own `this.props`. ' +
- 'Please file an issue.',
- getComponentName(finishedWork.type) || 'instance',
- );
- }
- if (instance.state !== finishedWork.memoizedState) {
- console.error(
- 'Expected %s state to match memoized state before ' +
- 'processing the update queue. ' +
- 'This might either be because of a bug in React, or because ' +
- 'a component reassigns its own `this.state`. ' +
- 'Please file an issue.',
- getComponentName(finishedWork.type) || 'instance',
- );
+ case HostRoot: {
+ // TODO: I think this is now always non-null by the time it reaches the
+ // commit phase. Consider removing the type check.
+ const updateQueue: UpdateQueue<
+ *,
+ > | null = (finishedWork.updateQueue: any);
+ if (updateQueue !== null) {
+ let instance = null;
+ if (finishedWork.child !== null) {
+ switch (finishedWork.child.tag) {
+ case HostComponent:
+ instance = getPublicInstance(finishedWork.child.stateNode);
+ break;
+ case ClassComponent:
+ instance = finishedWork.child.stateNode;
+ break;
}
}
+ commitUpdateQueue(finishedWork, updateQueue, instance);
}
- // We could update instance props and state here,
- // but instead we rely on them being set during last render.
- // TODO: revisit this when we implement resuming.
- commitUpdateQueue(finishedWork, updateQueue, instance);
+ break;
}
- return;
- }
- case HostRoot: {
- // TODO: I think this is now always non-null by the time it reaches the
- // commit phase. Consider removing the type check.
- const updateQueue: UpdateQueue<
- *,
- > | null = (finishedWork.updateQueue: any);
- if (updateQueue !== null) {
- let instance = null;
- if (finishedWork.child !== null) {
- switch (finishedWork.child.tag) {
- case HostComponent:
- instance = getPublicInstance(finishedWork.child.stateNode);
- break;
- case ClassComponent:
- instance = finishedWork.child.stateNode;
- break;
- }
+ case HostComponent: {
+ const instance: Instance = finishedWork.stateNode;
+
+ // Renderers may schedule work to be done after host components are mounted
+ // (eg DOM renderer may schedule auto-focus for inputs and form controls).
+ // These effects should only be committed when components are first mounted,
+ // aka when there is no current/alternate.
+ if (current === null && finishedWork.flags & Update) {
+ const type = finishedWork.type;
+ const props = finishedWork.memoizedProps;
+ commitMount(instance, type, props, finishedWork);
}
- commitUpdateQueue(finishedWork, updateQueue, instance);
- }
- return;
- }
- case HostComponent: {
- const instance: Instance = finishedWork.stateNode;
- // Renderers may schedule work to be done after host components are mounted
- // (eg DOM renderer may schedule auto-focus for inputs and form controls).
- // These effects should only be committed when components are first mounted,
- // aka when there is no current/alternate.
- if (current === null && finishedWork.flags & Update) {
- const type = finishedWork.type;
- const props = finishedWork.memoizedProps;
- commitMount(instance, type, props, finishedWork);
+ break;
}
+ case HostText: {
+ // We have no life-cycles associated with text.
+ break;
+ }
+ case HostPortal: {
+ // We have no life-cycles associated with portals.
+ break;
+ }
+ case Profiler: {
+ if (enableProfilerTimer) {
+ const {onCommit, onRender} = finishedWork.memoizedProps;
+ const {effectDuration} = finishedWork.stateNode;
- return;
- }
- case HostText: {
- // We have no life-cycles associated with text.
- return;
- }
- case HostPortal: {
- // We have no life-cycles associated with portals.
- return;
- }
- case Profiler: {
- if (enableProfilerTimer) {
- const {onCommit, onRender} = finishedWork.memoizedProps;
- const {effectDuration} = finishedWork.stateNode;
-
- const commitTime = getCommitTime();
-
- let phase = current === null ? 'mount' : 'update';
- if (enableProfilerNestedUpdatePhase) {
- if (isCurrentUpdateNested()) {
- phase = 'nested-update';
- }
- }
+ const commitTime = getCommitTime();
- if (typeof onRender === 'function') {
- if (enableSchedulerTracing) {
- onRender(
- finishedWork.memoizedProps.id,
- phase,
- finishedWork.actualDuration,
- finishedWork.treeBaseDuration,
- finishedWork.actualStartTime,
- commitTime,
- finishedRoot.memoizedInteractions,
- );
- } else {
- onRender(
- finishedWork.memoizedProps.id,
- phase,
- finishedWork.actualDuration,
- finishedWork.treeBaseDuration,
- finishedWork.actualStartTime,
- commitTime,
- );
+ let phase = current === null ? 'mount' : 'update';
+ if (enableProfilerNestedUpdatePhase) {
+ if (isCurrentUpdateNested()) {
+ phase = 'nested-update';
+ }
}
- }
- if (enableProfilerCommitHooks) {
- if (typeof onCommit === 'function') {
+ if (typeof onRender === 'function') {
if (enableSchedulerTracing) {
- onCommit(
+ onRender(
finishedWork.memoizedProps.id,
phase,
- effectDuration,
+ finishedWork.actualDuration,
+ finishedWork.treeBaseDuration,
+ finishedWork.actualStartTime,
commitTime,
finishedRoot.memoizedInteractions,
);
} else {
- onCommit(
+ onRender(
finishedWork.memoizedProps.id,
phase,
- effectDuration,
+ finishedWork.actualDuration,
+ finishedWork.treeBaseDuration,
+ finishedWork.actualStartTime,
commitTime,
);
}
}
- // Schedule a passive effect for this Profiler to call onPostCommit hooks.
- // This effect should be scheduled even if there is no onPostCommit callback for this Profiler,
- // because the effect is also where times bubble to parent Profilers.
- enqueuePendingPassiveProfilerEffect(finishedWork);
+ if (enableProfilerCommitHooks) {
+ if (typeof onCommit === 'function') {
+ if (enableSchedulerTracing) {
+ onCommit(
+ finishedWork.memoizedProps.id,
+ phase,
+ effectDuration,
+ commitTime,
+ finishedRoot.memoizedInteractions,
+ );
+ } else {
+ onCommit(
+ finishedWork.memoizedProps.id,
+ phase,
+ effectDuration,
+ commitTime,
+ );
+ }
+ }
- // Propagate layout effect durations to the next nearest Profiler ancestor.
- // Do not reset these values until the next render so DevTools has a chance to read them first.
- let parentFiber = finishedWork.return;
- while (parentFiber !== null) {
- if (parentFiber.tag === Profiler) {
- const parentStateNode = parentFiber.stateNode;
- parentStateNode.effectDuration += effectDuration;
- break;
+ // Schedule a passive effect for this Profiler to call onPostCommit hooks.
+ // This effect should be scheduled even if there is no onPostCommit callback for this Profiler,
+ // because the effect is also where times bubble to parent Profilers.
+ enqueuePendingPassiveProfilerEffect(finishedWork);
+
+ // Propagate layout effect durations to the next nearest Profiler ancestor.
+ // Do not reset these values until the next render so DevTools has a chance to read them first.
+ let parentFiber = finishedWork.return;
+ while (parentFiber !== null) {
+ if (parentFiber.tag === Profiler) {
+ const parentStateNode = parentFiber.stateNode;
+ parentStateNode.effectDuration += effectDuration;
+ break;
+ }
+ parentFiber = parentFiber.return;
}
- parentFiber = parentFiber.return;
}
}
+ break;
}
- return;
+ case SuspenseComponent: {
+ commitSuspenseHydrationCallbacks(finishedRoot, finishedWork);
+ break;
+ }
+ case SuspenseListComponent:
+ case IncompleteClassComponent:
+ case FundamentalComponent:
+ case ScopeComponent:
+ case OffscreenComponent:
+ case LegacyHiddenComponent:
+ break;
+ default:
+ invariant(
+ false,
+ 'This unit of work tag should not have side-effects. This error is ' +
+ 'likely caused by a bug in React. Please file an issue.',
+ );
}
- case SuspenseComponent: {
- commitSuspenseHydrationCallbacks(finishedRoot, finishedWork);
- return;
+ }
+
+ if (enableScopeAPI) {
+ // TODO: This is a temporary solution that allowed us to transition away
+ // from React Flare on www.
+ if (finishedWork.flags & Ref && finishedWork.tag !== ScopeComponent) {
+ commitAttachRef(finishedWork);
+ }
+ } else {
+ if (finishedWork.flags & Ref) {
+ commitAttachRef(finishedWork);
}
- case SuspenseListComponent:
- case IncompleteClassComponent:
- case FundamentalComponent:
- case ScopeComponent:
- case OffscreenComponent:
- case LegacyHiddenComponent:
- return;
}
- invariant(
- false,
- 'This unit of work tag should not have side-effects. This error is ' +
- 'likely caused by a bug in React. Please file an issue.',
- );
}
function hideOrUnhideAllChildren(finishedWork, isHidden) {
@@ -1823,12 +1841,88 @@ function commitResetTextContent(current: Fiber) {
resetTextContent(current.stateNode);
}
+export function commitLayoutEffects(
+ finishedWork: Fiber,
+ root: FiberRoot,
+ committedLanes: Lanes,
+): void {
+ nextEffect = finishedWork;
+ commitLayoutEffects_begin(finishedWork, root, committedLanes);
+}
+
+function commitLayoutEffects_begin(
+ subtreeRoot: Fiber,
+ root: FiberRoot,
+ committedLanes: Lanes,
+) {
+ while (nextEffect !== null) {
+ const fiber = nextEffect;
+ const firstChild = fiber.child;
+ if ((fiber.subtreeFlags & LayoutMask) !== NoFlags && firstChild !== null) {
+ ensureCorrectReturnPointer(firstChild, fiber);
+ nextEffect = firstChild;
+ } else {
+ commitLayoutMountEffects_complete(subtreeRoot, root, committedLanes);
+ }
+ }
+}
+
+function commitLayoutMountEffects_complete(
+ subtreeRoot: Fiber,
+ root: FiberRoot,
+ committedLanes: Lanes,
+) {
+ while (nextEffect !== null) {
+ const fiber = nextEffect;
+ if ((fiber.flags & LayoutMask) !== NoFlags) {
+ const current = fiber.alternate;
+ if (__DEV__) {
+ setCurrentDebugFiberInDEV(fiber);
+ invokeGuardedCallback(
+ null,
+ commitLayoutEffectOnFiber,
+ null,
+ root,
+ current,
+ fiber,
+ committedLanes,
+ );
+ if (hasCaughtError()) {
+ const error = clearCaughtError();
+ captureCommitPhaseError(fiber, error);
+ }
+ resetCurrentDebugFiberInDEV();
+ } else {
+ try {
+ commitLayoutEffectOnFiber(root, current, fiber, committedLanes);
+ } catch (error) {
+ captureCommitPhaseError(fiber, error);
+ }
+ }
+ }
+
+ if (fiber === subtreeRoot) {
+ nextEffect = null;
+ return;
+ }
+
+ const sibling = fiber.sibling;
+ if (sibling !== null) {
+ ensureCorrectReturnPointer(sibling, fiber.return);
+ nextEffect = sibling;
+ return;
+ }
+
+ nextEffect = fiber.return;
+ }
+}
+
export function commitPassiveMountEffects(
root: FiberRoot,
- firstChild: Fiber,
+ finishedWork: Fiber,
): void {
- nextEffect = firstChild;
- commitPassiveMountEffects_begin(firstChild, root);
+ nextEffect = finishedWork;
+ commitPassiveMountEffects_begin(finishedWork, root);
}
function commitPassiveMountEffects_begin(subtreeRoot: Fiber, root: FiberRoot) {
@@ -2094,7 +2188,6 @@ export {
commitPlacement,
commitDeletion,
commitWork,
- commitLifeCycles,
commitAttachRef,
commitDetachRef,
};
diff --git a/packages/react-reconciler/src/ReactFiberWorkLoop.new.js b/packages/react-reconciler/src/ReactFiberWorkLoop.new.js
index 0c50c804da36b..37f513f29d51f 100644
--- a/packages/react-reconciler/src/ReactFiberWorkLoop.new.js
+++ b/packages/react-reconciler/src/ReactFiberWorkLoop.new.js
@@ -131,7 +131,6 @@ import {
Ref,
ContentReset,
Snapshot,
- Callback,
Passive,
PassiveStatic,
Incomplete,
@@ -190,7 +189,7 @@ import {
} from './ReactFiberThrow.new';
import {
commitBeforeMutationLifeCycles as commitBeforeMutationEffectOnFiber,
- commitLifeCycles as commitLayoutEffectOnFiber,
+ commitLayoutEffects,
commitPlacement,
commitWork,
commitDeletion,
@@ -2073,28 +2072,24 @@ function commitRootImpl(root, renderPriorityLevel) {
// The next phase is the layout phase, where we call effects that read
// the host tree after it's been mutated. The idiomatic use case for this is
// layout, but class component lifecycles also fire here for legacy reasons.
- nextEffect = firstEffect;
- do {
- if (__DEV__) {
- invokeGuardedCallback(null, commitLayoutEffects, null, root, lanes);
- if (hasCaughtError()) {
- invariant(nextEffect !== null, 'Should be working on an effect.');
- const error = clearCaughtError();
- captureCommitPhaseError(nextEffect, error);
- nextEffect = nextEffect.nextEffect;
- }
- } else {
- try {
- commitLayoutEffects(root, lanes);
- } catch (error) {
- invariant(nextEffect !== null, 'Should be working on an effect.');
- captureCommitPhaseError(nextEffect, error);
- nextEffect = nextEffect.nextEffect;
- }
+ if (__DEV__) {
+ if (enableDebugTracing) {
+ logLayoutEffectsStarted(lanes);
}
- } while (nextEffect !== null);
+ }
+ if (enableSchedulingProfiler) {
+ markLayoutEffectsStarted(lanes);
+ }
+ commitLayoutEffects(finishedWork, root, lanes);
+ if (__DEV__) {
+ if (enableDebugTracing) {
+ logLayoutEffectsStopped();
+ }
+ }
- nextEffect = null;
+ if (enableSchedulingProfiler) {
+ markLayoutEffectsStopped();
+ }
if (enableProfilerTimer && enableProfilerNestedUpdateScheduledHook) {
rootCommittingMutationOrLayoutEffects = null;
@@ -2420,55 +2415,6 @@ function commitMutationEffects(
}
}
-function commitLayoutEffects(root: FiberRoot, committedLanes: Lanes) {
- if (__DEV__) {
- if (enableDebugTracing) {
- logLayoutEffectsStarted(committedLanes);
- }
- }
-
- if (enableSchedulingProfiler) {
- markLayoutEffectsStarted(committedLanes);
- }
-
- // TODO: Should probably move the bulk of this function to commitWork.
- while (nextEffect !== null) {
- setCurrentDebugFiberInDEV(nextEffect);
-
- const flags = nextEffect.flags;
-
- if (flags & (Update | Callback)) {
- const current = nextEffect.alternate;
- commitLayoutEffectOnFiber(root, current, nextEffect, committedLanes);
- }
-
- if (enableScopeAPI) {
- // TODO: This is a temporary solution that allowed us to transition away
- // from React Flare on www.
- if (flags & Ref && nextEffect.tag !== ScopeComponent) {
- commitAttachRef(nextEffect);
- }
- } else {
- if (flags & Ref) {
- commitAttachRef(nextEffect);
- }
- }
-
- resetCurrentDebugFiberInDEV();
- nextEffect = nextEffect.nextEffect;
- }
-
- if (__DEV__) {
- if (enableDebugTracing) {
- logLayoutEffectsStopped();
- }
- }
-
- if (enableSchedulingProfiler) {
- markLayoutEffectsStopped();
- }
-}
-
export function flushPassiveEffects(): boolean {
// Returns whether passive effects were flushed.
if (pendingPassiveEffectsRenderPriority !== NoSchedulerPriority) {
diff --git a/packages/react/src/__tests__/ReactDOMTracing-test.internal.js b/packages/react/src/__tests__/ReactDOMTracing-test.internal.js
index 5026605672fcb..bd097fea76548 100644
--- a/packages/react/src/__tests__/ReactDOMTracing-test.internal.js
+++ b/packages/react/src/__tests__/ReactDOMTracing-test.internal.js
@@ -152,7 +152,7 @@ describe('ReactDOMTracing', () => {
onInteractionScheduledWorkCompleted,
).toHaveBeenLastNotifiedOfInteraction(interaction);
- if (gate(flags => flags.dfsEffectsRefactor)) {
+ if (gate(flags => flags.enableUseJSStackToTrackPassiveDurations)) {
expect(onRender).toHaveBeenCalledTimes(3);
} else {
// TODO: This is 4 instead of 3 because this update was scheduled at
@@ -310,7 +310,7 @@ describe('ReactDOMTracing', () => {
expect(
onInteractionScheduledWorkCompleted,
).toHaveBeenLastNotifiedOfInteraction(interaction);
- if (gate(flags => flags.dfsEffectsRefactor)) {
+ if (gate(flags => flags.enableUseJSStackToTrackPassiveDurations)) {
expect(onRender).toHaveBeenCalledTimes(3);
} else {
// TODO: This is 4 instead of 3 because this update was scheduled at
diff --git a/packages/react/src/__tests__/ReactProfiler-test.internal.js b/packages/react/src/__tests__/ReactProfiler-test.internal.js
index eb0c69537df4b..8387319511b55 100644
--- a/packages/react/src/__tests__/ReactProfiler-test.internal.js
+++ b/packages/react/src/__tests__/ReactProfiler-test.internal.js
@@ -368,7 +368,7 @@ describe('Profiler', () => {
renderer.update();
- if (gate(flags => flags.dfsEffectsRefactor)) {
+ if (gate(flags => flags.enableUseJSStackToTrackPassiveDurations)) {
// None of the Profiler's subtree was rendered because App bailed out before the Profiler.
// So we expect onRender not to be called.
expect(callback).not.toHaveBeenCalled();
@@ -4383,7 +4383,7 @@ describe('Profiler', () => {
// because the resolved suspended subtree doesn't contain any passive effects.
// If or its decendents had a passive effect,
// onPostCommit would be called again.
- if (gate(flags => flags.dfsEffectsRefactor)) {
+ if (gate(flags => flags.enableUseJSStackToTrackPassiveDurations)) {
expect(Scheduler).toFlushAndYield([]);
} else {
expect(Scheduler).toFlushAndYield(['onPostCommit']);
@@ -4874,7 +4874,7 @@ describe('Profiler', () => {
});
if (__DEV__) {
- // @gate dfsEffectsRefactor
+ // @gate enableUseJSStackToTrackPassiveDurations
// @gate enableDoubleInvokingEffects
it('double invoking does not disconnect wrapped async work', () => {
ReactFeatureFlags.enableDoubleInvokingEffects = true;
diff --git a/scripts/jest/TestFlags.js b/scripts/jest/TestFlags.js
index f869620f03290..d7e82312dd2a5 100644
--- a/scripts/jest/TestFlags.js
+++ b/scripts/jest/TestFlags.js
@@ -45,9 +45,10 @@ const environmentFlags = {
// Use this for tests that are known to be broken.
FIXME: false,
- // Turn this flag back on (or delete) once the effect list is removed in favor
- // of a depth-first traversal using `subtreeTags`.
- dfsEffectsRefactor: false,
+ // Turn these flags back on (or delete) once the effect list is removed in
+ // favor of a depth-first traversal using `subtreeTags`.
+ dfsEffectsRefactor: __VARIANT__,
+ enableUseJSStackToTrackPassiveDurations: false,
};
function getTestFlags() {