diff --git a/packages/react-reconciler/src/ReactFiberCommitWork.js b/packages/react-reconciler/src/ReactFiberCommitWork.js index df16eb96ef216..83922deed4b26 100644 --- a/packages/react-reconciler/src/ReactFiberCommitWork.js +++ b/packages/react-reconciler/src/ReactFiberCommitWork.js @@ -2209,6 +2209,8 @@ function recursivelyTraverseLayoutEffects( } export function disappearLayoutEffects(finishedWork: Fiber) { + const prevEffectStart = pushComponentEffectStart(); + switch (finishedWork.tag) { case FunctionComponent: case ForwardRef: @@ -2266,6 +2268,25 @@ export function disappearLayoutEffects(finishedWork: Fiber) { break; } } + + if ( + enableProfilerTimer && + enableProfilerCommitHooks && + enableComponentPerformanceTrack && + (finishedWork.mode & ProfileMode) !== NoMode && + componentEffectStartTime >= 0 && + componentEffectEndTime >= 0 && + componentEffectDuration > 0.05 + ) { + logComponentEffect( + finishedWork, + componentEffectStartTime, + componentEffectEndTime, + componentEffectDuration, + ); + } + + popComponentEffectStart(prevEffectStart); } function recursivelyTraverseDisappearLayoutEffects(parentFiber: Fiber) { @@ -2286,6 +2307,8 @@ export function reappearLayoutEffects( // node was reused. includeWorkInProgressEffects: boolean, ) { + const prevEffectStart = pushComponentEffectStart(); + // Turn on layout effects in a tree that previously disappeared. const flags = finishedWork.flags; switch (finishedWork.tag) { @@ -2421,6 +2444,25 @@ export function reappearLayoutEffects( break; } } + + if ( + enableProfilerTimer && + enableProfilerCommitHooks && + enableComponentPerformanceTrack && + (finishedWork.mode & ProfileMode) !== NoMode && + componentEffectStartTime >= 0 && + componentEffectEndTime >= 0 && + componentEffectDuration > 0.05 + ) { + logComponentEffect( + finishedWork, + componentEffectStartTime, + componentEffectEndTime, + componentEffectDuration, + ); + } + + popComponentEffectStart(prevEffectStart); } function recursivelyTraverseReappearLayoutEffects( @@ -2846,6 +2888,7 @@ function commitPassiveMountOnFiber( finishedWork, committedLanes, committedTransitions, + endTime, ); } else { // Legacy Mode: Fire the effects even if the tree is hidden. @@ -2884,6 +2927,7 @@ function commitPassiveMountOnFiber( committedLanes, committedTransitions, includeWorkInProgressEffects, + endTime, ); } } @@ -2963,6 +3007,7 @@ function recursivelyTraverseReconnectPassiveEffects( committedLanes: Lanes, committedTransitions: Array | null, includeWorkInProgressEffects: boolean, + endTime: number, ) { // This function visits both newly finished work and nodes that were re-used // from a previously committed tree. We cannot check non-static flags if the @@ -2974,14 +3019,30 @@ function recursivelyTraverseReconnectPassiveEffects( // TODO (Offscreen) Check: flags & (RefStatic | LayoutStatic) let child = parentFiber.child; while (child !== null) { - reconnectPassiveEffects( - finishedRoot, - child, - committedLanes, - committedTransitions, - childShouldIncludeWorkInProgressEffects, - ); - child = child.sibling; + if (enableProfilerTimer && enableComponentPerformanceTrack) { + const nextSibling = child.sibling; + reconnectPassiveEffects( + finishedRoot, + child, + committedLanes, + committedTransitions, + childShouldIncludeWorkInProgressEffects, + nextSibling !== null + ? ((nextSibling.actualStartTime: any): number) + : endTime, + ); + child = nextSibling; + } else { + reconnectPassiveEffects( + finishedRoot, + child, + committedLanes, + committedTransitions, + childShouldIncludeWorkInProgressEffects, + endTime, + ); + child = child.sibling; + } } } @@ -2994,7 +3055,28 @@ export function reconnectPassiveEffects( // from a previously committed tree. We cannot check non-static flags if the // node was reused. includeWorkInProgressEffects: boolean, + endTime: number, // Profiling-only. The start time of the next Fiber or root completion. ) { + const prevEffectStart = pushComponentEffectStart(); + + // If this component rendered in Profiling mode (DEV or in Profiler component) then log its + // render time. We do this after the fact in the passive effect to avoid the overhead of this + // getting in the way of the render characteristics and avoid the overhead of unwinding + // uncommitted renders. + if ( + enableProfilerTimer && + enableComponentPerformanceTrack && + (finishedWork.mode & ProfileMode) !== NoMode && + ((finishedWork.actualStartTime: any): number) > 0 && + (finishedWork.flags & PerformedWork) !== NoFlags + ) { + logComponentRender( + finishedWork, + ((finishedWork.actualStartTime: any): number), + endTime, + ); + } + const flags = finishedWork.flags; switch (finishedWork.tag) { case FunctionComponent: @@ -3006,6 +3088,7 @@ export function reconnectPassiveEffects( committedLanes, committedTransitions, includeWorkInProgressEffects, + endTime, ); // TODO: Check for PassiveStatic flag commitHookPassiveMountEffects(finishedWork, HookPassive); @@ -3025,6 +3108,7 @@ export function reconnectPassiveEffects( committedLanes, committedTransitions, includeWorkInProgressEffects, + endTime, ); if (includeWorkInProgressEffects && flags & Passive) { @@ -3051,6 +3135,7 @@ export function reconnectPassiveEffects( committedLanes, committedTransitions, includeWorkInProgressEffects, + endTime, ); } else { if (disableLegacyMode || finishedWork.mode & ConcurrentMode) { @@ -3064,6 +3149,7 @@ export function reconnectPassiveEffects( finishedWork, committedLanes, committedTransitions, + endTime, ); } else { // Legacy Mode: Fire the effects even if the tree is hidden. @@ -3074,6 +3160,7 @@ export function reconnectPassiveEffects( committedLanes, committedTransitions, includeWorkInProgressEffects, + endTime, ); } } @@ -3093,6 +3180,7 @@ export function reconnectPassiveEffects( committedLanes, committedTransitions, includeWorkInProgressEffects, + endTime, ); } @@ -3110,6 +3198,7 @@ export function reconnectPassiveEffects( committedLanes, committedTransitions, includeWorkInProgressEffects, + endTime, ); if (includeWorkInProgressEffects && flags & Passive) { // TODO: Pass `current` as argument to this function @@ -3126,6 +3215,7 @@ export function reconnectPassiveEffects( committedLanes, committedTransitions, includeWorkInProgressEffects, + endTime, ); if (includeWorkInProgressEffects && flags & Passive) { commitTracingMarkerPassiveMountEffect(finishedWork); @@ -3141,10 +3231,30 @@ export function reconnectPassiveEffects( committedLanes, committedTransitions, includeWorkInProgressEffects, + endTime, ); break; } } + + if ( + enableProfilerTimer && + enableProfilerCommitHooks && + enableComponentPerformanceTrack && + (finishedWork.mode & ProfileMode) !== NoMode && + componentEffectStartTime >= 0 && + componentEffectEndTime >= 0 && + componentEffectDuration > 0.05 + ) { + logComponentEffect( + finishedWork, + componentEffectStartTime, + componentEffectEndTime, + componentEffectDuration, + ); + } + + popComponentEffectStart(prevEffectStart); } function recursivelyTraverseAtomicPassiveEffects( @@ -3152,6 +3262,7 @@ function recursivelyTraverseAtomicPassiveEffects( parentFiber: Fiber, committedLanes: Lanes, committedTransitions: Array | null, + endTime: number, // Profiling-only. The start time of the next Fiber or root completion. ) { // "Atomic" effects are ones that need to fire on every commit, even during // pre-rendering. We call this function when traversing a hidden tree whose @@ -3160,13 +3271,28 @@ function recursivelyTraverseAtomicPassiveEffects( if (parentFiber.subtreeFlags & PassiveMask) { let child = parentFiber.child; while (child !== null) { - commitAtomicPassiveEffects( - finishedRoot, - child, - committedLanes, - committedTransitions, - ); - child = child.sibling; + if (enableProfilerTimer && enableComponentPerformanceTrack) { + const nextSibling = child.sibling; + commitAtomicPassiveEffects( + finishedRoot, + child, + committedLanes, + committedTransitions, + nextSibling !== null + ? ((nextSibling.actualStartTime: any): number) + : endTime, + ); + child = nextSibling; + } else { + commitAtomicPassiveEffects( + finishedRoot, + child, + committedLanes, + committedTransitions, + endTime, + ); + child = child.sibling; + } } } } @@ -3176,7 +3302,24 @@ function commitAtomicPassiveEffects( finishedWork: Fiber, committedLanes: Lanes, committedTransitions: Array | null, + endTime: number, // Profiling-only. The start time of the next Fiber or root completion. ) { + // If this component rendered in Profiling mode (DEV or in Profiler component) then log its + // render time. A render can happen even if the subtree is offscreen. + if ( + enableProfilerTimer && + enableComponentPerformanceTrack && + (finishedWork.mode & ProfileMode) !== NoMode && + ((finishedWork.actualStartTime: any): number) > 0 && + (finishedWork.flags & PerformedWork) !== NoFlags + ) { + logComponentRender( + finishedWork, + ((finishedWork.actualStartTime: any): number), + endTime, + ); + } + // "Atomic" effects are ones that need to fire on every commit, even during // pre-rendering. We call this function when traversing a hidden tree whose // regular effects are currently disconnected. @@ -3188,6 +3331,7 @@ function commitAtomicPassiveEffects( finishedWork, committedLanes, committedTransitions, + endTime, ); if (flags & Passive) { // TODO: Pass `current` as argument to this function @@ -3203,6 +3347,7 @@ function commitAtomicPassiveEffects( finishedWork, committedLanes, committedTransitions, + endTime, ); if (flags & Passive) { // TODO: Pass `current` as argument to this function @@ -3217,6 +3362,7 @@ function commitAtomicPassiveEffects( finishedWork, committedLanes, committedTransitions, + endTime, ); break; } @@ -3591,6 +3737,8 @@ function commitPassiveUnmountInsideDeletedTreeOnFiber( current: Fiber, nearestMountedAncestor: Fiber | null, ): void { + const prevEffectStart = pushComponentEffectStart(); + switch (current.tag) { case FunctionComponent: case ForwardRef: @@ -3702,6 +3850,25 @@ function commitPassiveUnmountInsideDeletedTreeOnFiber( break; } } + + if ( + enableProfilerTimer && + enableProfilerCommitHooks && + enableComponentPerformanceTrack && + (current.mode & ProfileMode) !== NoMode && + componentEffectStartTime >= 0 && + componentEffectEndTime >= 0 && + componentEffectDuration > 0.05 + ) { + logComponentEffect( + current, + componentEffectStartTime, + componentEffectEndTime, + componentEffectDuration, + ); + } + + popComponentEffectStart(prevEffectStart); } export function invokeLayoutEffectMountInDEV(fiber: Fiber): void { diff --git a/packages/react-reconciler/src/ReactFiberWorkLoop.js b/packages/react-reconciler/src/ReactFiberWorkLoop.js index d524dd8599621..a71eb543cfe5d 100644 --- a/packages/react-reconciler/src/ReactFiberWorkLoop.js +++ b/packages/react-reconciler/src/ReactFiberWorkLoop.js @@ -4139,7 +4139,7 @@ function doubleInvokeEffectsOnFiber( } reappearLayoutEffects(root, fiber.alternate, fiber, false); if (shouldDoubleInvokePassiveEffects) { - reconnectPassiveEffects(root, fiber, NoLanes, null, false); + reconnectPassiveEffects(root, fiber, NoLanes, null, false, 0); } } finally { setIsStrictModeForDevtools(false);