From 6406ca89c6012a6a726af171a3d5c2d36862bd99 Mon Sep 17 00:00:00 2001 From: Brian Vaughn Date: Fri, 25 Sep 2020 12:55:45 -0400 Subject: [PATCH] Moved commit layout effects code from work loop to commit work Merged the three functions responsible for handling layout effects (commitLayoutEffects, commitLayoutEffectsImpl, and commitLifeCycles) into two functions (recursivelyCommitLayoutEffects and commitLayoutEffectsForFiber) and relocated them into the work loop. --- .../src/ReactFiberCommitWork.new.js | 601 +++++++++++------- .../src/ReactFiberWorkLoop.new.js | 102 +-- 2 files changed, 368 insertions(+), 335 deletions(-) diff --git a/packages/react-reconciler/src/ReactFiberCommitWork.new.js b/packages/react-reconciler/src/ReactFiberCommitWork.new.js index 8f975bab91dfc3..2416dcc5b15b65 100644 --- a/packages/react-reconciler/src/ReactFiberCommitWork.new.js +++ b/packages/react-reconciler/src/ReactFiberCommitWork.new.js @@ -70,11 +70,16 @@ import { Snapshot, Update, Callback, + LayoutMask, PassiveMask, + Ref, } from './ReactFiberFlags'; import getComponentName from 'shared/getComponentName'; import invariant from 'shared/invariant'; - +import { + resetCurrentFiber as resetCurrentDebugFiberInDEV, + setCurrentFiber as setCurrentDebugFiberInDEV, +} from './ReactCurrentFiber'; import {onCommitUnmount} from './ReactFiberDevToolsHook.new'; import {resolveDefaultProps} from './ReactFiberLazyComponent.new'; import { @@ -130,6 +135,9 @@ import { } from './ReactHookEffectTags'; import {didWarnAboutReassigningProps} from './ReactFiberBeginWork.new'; +// Used to avoid traversing the return path to find the nearest Profiler ancestor during commit. +let nearestProfilerOnStack: Fiber | null = null; + let didWarnAboutUndefinedSnapshotBeforeUpdate: Set | null = null; if (__DEV__) { didWarnAboutUndefinedSnapshotBeforeUpdate = new Set(); @@ -432,98 +440,260 @@ function commitProfilerPassiveEffect( } } -function commitLifeCycles( - finishedRoot: FiberRoot, - current: Fiber | null, +function recursivelyCommitLayoutEffects( finishedWork: Fiber, + root: FiberRoot, committedLanes: Lanes, -): void { +) { switch (finishedWork.tag) { - case FunctionComponent: - case ForwardRef: - case SimpleMemoComponent: - case Block: { - // 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); + case Profiler: { + let prevProfilerOnStack = null; + if (enableProfilerTimer && enableProfilerCommitHooks) { + prevProfilerOnStack = nearestProfilerOnStack; + nearestProfilerOnStack = finishedWork; + } + + let child = finishedWork.child; + while (child !== null) { + const primaryFlags = child.flags & LayoutMask; + const primarySubtreeFlags = child.subtreeFlags & LayoutMask; + if (primaryFlags !== NoFlags || primarySubtreeFlags !== NoFlags) { + recursivelyCommitLayoutEffects(child, root, committedLanes); } + child = child.sibling; + } + + if (__DEV__) { + setCurrentDebugFiberInDEV(finishedWork); + invokeGuardedCallback( + null, + commitLayoutEffectsForFiber, + null, + finishedWork, + root, + committedLanes, + ); + if (hasCaughtError()) { + const error = clearCaughtError(); + captureCommitPhaseError(finishedWork, finishedWork.return, error); + } + resetCurrentDebugFiberInDEV(); } else { - commitHookEffectListMount(HookLayout | HookHasEffect, finishedWork); + try { + commitLayoutEffectsForFiber(finishedWork, root, committedLanes); + } catch (error) { + captureCommitPhaseError(finishedWork, finishedWork.return, error); + } } - if ((finishedWork.subtreeFlags & PassiveMask) !== NoFlags) { - schedulePassiveEffectCallback(); + if (enableProfilerTimer && enableProfilerCommitHooks) { + // 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. + if (prevProfilerOnStack !== null) { + prevProfilerOnStack.stateNode.effectDuration += + finishedWork.stateNode.effectDuration; + } + + nearestProfilerOnStack = prevProfilerOnStack; } - return; + 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__) { + + // case Offscreen: { + // TODO: Fast path to invoke all nested layout effects when Offscren goes from hidden to visible. + // break; + // } + + default: { + let child = finishedWork.child; + while (child !== null) { + const primaryFlags = child.flags & LayoutMask; + const primarySubtreeFlags = child.subtreeFlags & LayoutMask; + if (primaryFlags !== NoFlags || primarySubtreeFlags !== NoFlags) { + recursivelyCommitLayoutEffects(child, root, committedLanes); + } + child = child.sibling; + } + + if (__DEV__) { + setCurrentDebugFiberInDEV(finishedWork); + invokeGuardedCallback( + null, + commitLayoutEffectsForFiber, + null, + finishedWork, + root, + committedLanes, + ); + if (hasCaughtError()) { + const error = clearCaughtError(); + captureCommitPhaseError(finishedWork, finishedWork.return, error); + } + resetCurrentDebugFiberInDEV(); + } else { + try { + commitLayoutEffectsForFiber(finishedWork, root, committedLanes); + } catch (error) { + captureCommitPhaseError(finishedWork, finishedWork.return, error); + } + } + break; + } + } +} + +function commitLayoutEffectsForFiber( + finishedWork: Fiber, + finishedRoot: FiberRoot, + committedLanes: Lanes, +) { + const {alternate: current, flags, tag} = finishedWork; + + if (flags & (Update | Callback)) { + switch (tag) { + case FunctionComponent: + case ForwardRef: + case SimpleMemoComponent: + case Block: { + // 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); + } + + if ((finishedWork.subtreeFlags & PassiveMask) !== NoFlags) { + schedulePassiveEffectCallback(); + } + break; + } + case ClassComponent: { + const instance = finishedWork.stateNode; + if (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 && @@ -532,7 +702,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.', @@ -542,7 +712,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.', @@ -551,196 +721,151 @@ 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 && 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 flags = finishedWork.flags; - - const commitTime = getCommitTime(); - - const OnRenderFlag = Update; - const OnCommitFlag = Callback; + const commitTime = getCommitTime(); - if ( - (flags & OnRenderFlag) !== NoFlags && - typeof onRender === 'function' - ) { - if (enableSchedulerTracing) { - onRender( - finishedWork.memoizedProps.id, - current === null ? 'mount' : 'update', - finishedWork.actualDuration, - finishedWork.treeBaseDuration, - finishedWork.actualStartTime, - commitTime, - finishedRoot.memoizedInteractions, - ); - } else { - onRender( - finishedWork.memoizedProps.id, - current === null ? 'mount' : 'update', - finishedWork.actualDuration, - finishedWork.treeBaseDuration, - finishedWork.actualStartTime, - commitTime, - ); - } - } + const OnRenderFlag = Update; + const OnCommitFlag = Callback; - if (enableProfilerCommitHooks) { if ( - (flags & OnCommitFlag) !== NoFlags && - typeof onCommit === 'function' + (flags & OnRenderFlag) !== NoFlags && + typeof onRender === 'function' ) { if (enableSchedulerTracing) { - onCommit( + onRender( finishedWork.memoizedProps.id, current === null ? 'mount' : 'update', - effectDuration, + finishedWork.actualDuration, + finishedWork.treeBaseDuration, + finishedWork.actualStartTime, commitTime, finishedRoot.memoizedInteractions, ); } else { - onCommit( + onRender( finishedWork.memoizedProps.id, current === null ? 'mount' : 'update', - effectDuration, + finishedWork.actualDuration, + finishedWork.treeBaseDuration, + finishedWork.actualStartTime, commitTime, ); } } + + if (enableProfilerCommitHooks) { + if ( + (flags & OnCommitFlag) !== NoFlags && + typeof onCommit === 'function' + ) { + if (enableSchedulerTracing) { + onCommit( + finishedWork.memoizedProps.id, + current === null ? 'mount' : 'update', + effectDuration, + commitTime, + finishedRoot.memoizedInteractions, + ); + } else { + onCommit( + finishedWork.memoizedProps.id, + current === null ? 'mount' : 'update', + effectDuration, + commitTime, + ); + } + } + } } + 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 (flags & Ref && tag !== ScopeComponent) { + commitAttachRef(finishedWork); + } + } else { + if (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) { @@ -1990,7 +2115,6 @@ export { commitPlacement, commitDeletion, commitWork, - commitLifeCycles, commitAttachRef, commitDetachRef, commitPassiveUnmount, @@ -2000,4 +2124,5 @@ export { invokeLayoutEffectUnmountInDEV, invokePassiveEffectMountInDEV, invokePassiveEffectUnmountInDEV, + recursivelyCommitLayoutEffects, }; diff --git a/packages/react-reconciler/src/ReactFiberWorkLoop.new.js b/packages/react-reconciler/src/ReactFiberWorkLoop.new.js index 9721378f2844d6..4997f059b57eeb 100644 --- a/packages/react-reconciler/src/ReactFiberWorkLoop.new.js +++ b/packages/react-reconciler/src/ReactFiberWorkLoop.new.js @@ -129,7 +129,6 @@ import { Ref, ContentReset, Snapshot, - Callback, Passive, PassiveStatic, Incomplete, @@ -193,7 +192,6 @@ import { } from './ReactFiberThrow.new'; import { commitBeforeMutationLifeCycles as commitBeforeMutationEffectOnFiber, - commitLifeCycles as commitLayoutEffectOnFiber, commitPlacement, commitWork, commitDeletion, @@ -208,6 +206,7 @@ import { invokePassiveEffectMountInDEV, invokeLayoutEffectUnmountInDEV, invokePassiveEffectUnmountInDEV, + recursivelyCommitLayoutEffects, } from './ReactFiberCommitWork.new'; import {enqueueUpdate} from './ReactUpdateQueue.new'; import {resetContextDependencies} from './ReactFiberNewContext.new'; @@ -328,6 +327,9 @@ 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; } @@ -376,9 +378,6 @@ let isFlushingPassiveEffects = false; let focusedInstanceHandle: null | Fiber = null; let shouldFireAfterActiveInstanceBlur: boolean = false; -// Used to avoid traversing the return path to find the nearest Profiler ancestor during commit. -let nearestProfilerOnStack: Fiber | null = null; - export function getWorkInProgressRoot(): FiberRoot | null { return workInProgressRoot; } @@ -1955,7 +1954,7 @@ function commitRootImpl(root, renderPriorityLevel) { markLayoutEffectsStarted(lanes); } - commitLayoutEffects(finishedWork, root, lanes); + recursivelyCommitLayoutEffects(finishedWork, root, lanes); if (__DEV__) { if (enableDebugTracing) { @@ -2373,97 +2372,6 @@ export function schedulePassiveEffectCallback() { } } -function commitLayoutEffects( - firstChild: Fiber, - root: FiberRoot, - committedLanes: Lanes, -) { - let fiber = firstChild; - while (fiber !== null) { - let prevProfilerOnStack = null; - if (enableProfilerTimer && enableProfilerCommitHooks) { - if (fiber.tag === Profiler) { - prevProfilerOnStack = nearestProfilerOnStack; - nearestProfilerOnStack = fiber; - } - } - - if (fiber.child !== null) { - const primarySubtreeFlags = fiber.subtreeFlags & LayoutMask; - if (primarySubtreeFlags !== NoFlags) { - commitLayoutEffects(fiber.child, root, committedLanes); - } - } - - if (__DEV__) { - setCurrentDebugFiberInDEV(fiber); - invokeGuardedCallback( - null, - commitLayoutEffectsImpl, - null, - fiber, - root, - committedLanes, - ); - if (hasCaughtError()) { - const error = clearCaughtError(); - captureCommitPhaseError(fiber, fiber.return, error); - } - resetCurrentDebugFiberInDEV(); - } else { - try { - commitLayoutEffectsImpl(fiber, root, committedLanes); - } catch (error) { - captureCommitPhaseError(fiber, fiber.return, error); - } - } - - if (enableProfilerTimer && enableProfilerCommitHooks) { - if (fiber.tag === Profiler) { - // 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. - if (prevProfilerOnStack !== null) { - prevProfilerOnStack.stateNode.effectDuration += - fiber.stateNode.effectDuration; - } - - nearestProfilerOnStack = prevProfilerOnStack; - } - } - - fiber = fiber.sibling; - } -} - -function commitLayoutEffectsImpl( - fiber: Fiber, - root: FiberRoot, - committedLanes: Lanes, -) { - const flags = fiber.flags; - - setCurrentDebugFiberInDEV(fiber); - - if (flags & (Update | Callback)) { - const current = fiber.alternate; - commitLayoutEffectOnFiber(root, current, fiber, committedLanes); - } - - if (enableScopeAPI) { - // TODO: This is a temporary solution that allowed us to transition away - // from React Flare on www. - if (flags & Ref && fiber.tag !== ScopeComponent) { - commitAttachRef(fiber); - } - } else { - if (flags & Ref) { - commitAttachRef(fiber); - } - } - - resetCurrentDebugFiberInDEV(); -} - export function flushPassiveEffects(): boolean { // Returns whether passive effects were flushed. if (pendingPassiveEffectsRenderPriority !== NoSchedulerPriority) {