From abd486f97711aec7ae8b1bcb59208f5d99278b0c Mon Sep 17 00:00:00 2001 From: Sebastian Markbage Date: Wed, 22 May 2024 13:25:26 -0400 Subject: [PATCH] Replace setCurrentDebugFiberInDEV with runWithFiberInDEV --- .../react-reconciler/src/ReactChildFiber.js | 44 ++- .../react-reconciler/src/ReactCurrentFiber.js | 34 ++- .../src/ReactFiberCommitWork.js | 254 ++++++++++++------ .../src/ReactFiberReconciler.js | 18 +- .../react-reconciler/src/ReactFiberThrow.js | 44 +-- .../src/ReactFiberWorkLoop.js | 159 +++++++---- .../src/ReactStrictModeWarnings.js | 12 +- 7 files changed, 342 insertions(+), 223 deletions(-) diff --git a/packages/react-reconciler/src/ReactChildFiber.js b/packages/react-reconciler/src/ReactChildFiber.js index 0f14af18af18e..610092715f8cf 100644 --- a/packages/react-reconciler/src/ReactChildFiber.js +++ b/packages/react-reconciler/src/ReactChildFiber.js @@ -62,10 +62,7 @@ import {pushTreeFork} from './ReactFiberTreeContext'; import {createThenableState, trackUsedThenable} from './ReactFiberThenable'; import {readContextDuringReconciliation} from './ReactFiberNewContext'; -import { - getCurrentFiber as getCurrentDebugFiberInDEV, - setCurrentFiber as setCurrentDebugFiberInDEV, -} from './ReactCurrentFiber'; +import {runWithFiberInDEV} from './ReactCurrentFiber'; // This tracks the thenables that are unwrapped during reconcilation. let thenableState: ThenableState | null = null; @@ -181,15 +178,14 @@ if (__DEV__) { const fiber = createFiberFromElement((child: any), returnFiber.mode, 0); fiber.return = returnFiber; - const prevDebugFiber = getCurrentDebugFiberInDEV(); - setCurrentDebugFiberInDEV(fiber); - console.error( - 'Each child in a list should have a unique "key" prop.' + - '%s%s See https://react.dev/link/warning-keys for more information.', - currentComponentErrorInfo, - childOwnerAppendix, - ); - setCurrentDebugFiberInDEV(prevDebugFiber); + runWithFiberInDEV(fiber, () => { + console.error( + 'Each child in a list should have a unique "key" prop.' + + '%s%s See https://react.dev/link/warning-keys for more information.', + currentComponentErrorInfo, + childOwnerAppendix, + ); + }); }; } @@ -212,14 +208,17 @@ function validateFragmentProps( fiber = createFiberFromElement(element, returnFiber.mode, 0); fiber.return = returnFiber; } - const prevDebugFiber = getCurrentDebugFiberInDEV(); - setCurrentDebugFiberInDEV(fiber); - console.error( - 'Invalid prop `%s` supplied to `React.Fragment`. ' + - 'React.Fragment can only have `key` and `children` props.', + runWithFiberInDEV( + fiber, + erroredKey => { + console.error( + 'Invalid prop `%s` supplied to `React.Fragment`. ' + + 'React.Fragment can only have `key` and `children` props.', + erroredKey, + ); + }, key, ); - setCurrentDebugFiberInDEV(prevDebugFiber); break; } } @@ -231,10 +230,9 @@ function validateFragmentProps( fiber = createFiberFromElement(element, returnFiber.mode, 0); fiber.return = returnFiber; } - const prevDebugFiber = getCurrentDebugFiberInDEV(); - setCurrentDebugFiberInDEV(fiber); - console.error('Invalid attribute `ref` supplied to `React.Fragment`.'); - setCurrentDebugFiberInDEV(prevDebugFiber); + runWithFiberInDEV(fiber, () => { + console.error('Invalid attribute `ref` supplied to `React.Fragment`.'); + }); } } } diff --git a/packages/react-reconciler/src/ReactCurrentFiber.js b/packages/react-reconciler/src/ReactCurrentFiber.js index c0ff5d16df4cb..773179f5e3194 100644 --- a/packages/react-reconciler/src/ReactCurrentFiber.js +++ b/packages/react-reconciler/src/ReactCurrentFiber.js @@ -41,16 +41,29 @@ function getCurrentFiberStackInDev(): string { return ''; } -export function resetCurrentDebugFiberInDEV() { - if (__DEV__) { - resetCurrentFiber(); - } -} - -export function setCurrentDebugFiberInDEV(fiber: Fiber | null) { +export function runWithFiberInDEV( + fiber: null | Fiber, + callback: (A0, A1, A2, A3, A4) => T, + arg0: A0, + arg1: A1, + arg2: A2, + arg3: A3, + arg4: A4, +): T { if (__DEV__) { + const previousFiber = current; setCurrentFiber(fiber); + try { + return callback(arg0, arg1, arg2, arg3, arg4); + } finally { + current = previousFiber; + } } + // These errors should never make it into a build so we don't need to encode them in codes.json + // eslint-disable-next-line react-internal/prod-error-codes + throw new Error( + 'runWithFiberInDEV should never be called in production. This is a bug in React.', + ); } export function resetCurrentFiber() { @@ -70,13 +83,6 @@ export function setCurrentFiber(fiber: Fiber | null) { current = fiber; } -export function getCurrentFiber(): Fiber | null { - if (__DEV__) { - return current; - } - return null; -} - export function setIsRendering(rendering: boolean) { if (__DEV__) { isRendering = rendering; diff --git a/packages/react-reconciler/src/ReactFiberCommitWork.js b/packages/react-reconciler/src/ReactFiberCommitWork.js index 5c7f845b96793..a8d37b5e44936 100644 --- a/packages/react-reconciler/src/ReactFiberCommitWork.js +++ b/packages/react-reconciler/src/ReactFiberCommitWork.js @@ -100,11 +100,7 @@ import { FormReset, } from './ReactFiberFlags'; import getComponentNameFromFiber from 'react-reconciler/src/getComponentNameFromFiber'; -import { - resetCurrentDebugFiberInDEV, - setCurrentDebugFiberInDEV, - getCurrentFiber as getCurrentDebugFiberInDEV, -} from './ReactCurrentFiber'; +import {runWithFiberInDEV} from './ReactCurrentFiber'; import {resolveClassComponentProps} from './ReactFiberClassComponent'; import { isCurrentUpdateNested, @@ -403,13 +399,15 @@ function commitBeforeMutationEffects_begin() { function commitBeforeMutationEffects_complete() { while (nextEffect !== null) { const fiber = nextEffect; - setCurrentDebugFiberInDEV(fiber); try { - commitBeforeMutationEffectsOnFiber(fiber); + if (__DEV__) { + runWithFiberInDEV(fiber, commitBeforeMutationEffectsOnFiber, fiber); + } else { + commitBeforeMutationEffectsOnFiber(fiber); + } } catch (error) { captureCommitPhaseError(fiber, fiber.return, error); } - resetCurrentDebugFiberInDEV(); const sibling = fiber.sibling; if (sibling !== null) { @@ -442,10 +440,6 @@ function commitBeforeMutationEffectsOnFiber(finishedWork: Fiber) { } } - if ((flags & Snapshot) !== NoFlags) { - setCurrentDebugFiberInDEV(finishedWork); - } - switch (finishedWork.tag) { case FunctionComponent: { if (enableUseEffectEventHook) { @@ -547,10 +541,6 @@ function commitBeforeMutationEffectsOnFiber(finishedWork: Fiber) { } } } - - if ((flags & Snapshot) !== NoFlags) { - resetCurrentDebugFiberInDEV(); - } } function commitBeforeMutationEffectsDeletion(deletion: Fiber) { @@ -2484,9 +2474,17 @@ export function commitMutationEffects( inProgressLanes = committedLanes; inProgressRoot = root; - setCurrentDebugFiberInDEV(finishedWork); - commitMutationEffectsOnFiber(finishedWork, root, committedLanes); - resetCurrentDebugFiberInDEV(); + if (__DEV__) { + runWithFiberInDEV( + finishedWork, + commitMutationEffectsOnFiber, + finishedWork, + root, + committedLanes, + ); + } else { + commitMutationEffectsOnFiber(finishedWork, root, committedLanes); + } inProgressLanes = null; inProgressRoot = null; @@ -2511,16 +2509,23 @@ function recursivelyTraverseMutationEffects( } } - const prevDebugFiber = getCurrentDebugFiberInDEV(); if (parentFiber.subtreeFlags & MutationMask) { let child = parentFiber.child; while (child !== null) { - setCurrentDebugFiberInDEV(child); - commitMutationEffectsOnFiber(child, root, lanes); + if (__DEV__) { + runWithFiberInDEV( + child, + commitMutationEffectsOnFiber, + child, + root, + lanes, + ); + } else { + commitMutationEffectsOnFiber(child, root, lanes); + } child = child.sibling; } } - setCurrentDebugFiberInDEV(prevDebugFiber); } let currentHoistableRoot: HoistableRoot | null = null; @@ -3125,10 +3130,19 @@ export function commitLayoutEffects( inProgressLanes = committedLanes; inProgressRoot = root; - setCurrentDebugFiberInDEV(finishedWork); const current = finishedWork.alternate; - commitLayoutEffectOnFiber(root, current, finishedWork, committedLanes); - resetCurrentDebugFiberInDEV(); + if (__DEV__) { + runWithFiberInDEV( + finishedWork, + commitLayoutEffectOnFiber, + root, + current, + finishedWork, + committedLanes, + ); + } else { + commitLayoutEffectOnFiber(root, current, finishedWork, committedLanes); + } inProgressLanes = null; inProgressRoot = null; @@ -3139,17 +3153,25 @@ function recursivelyTraverseLayoutEffects( parentFiber: Fiber, lanes: Lanes, ) { - const prevDebugFiber = getCurrentDebugFiberInDEV(); if (parentFiber.subtreeFlags & LayoutMask) { let child = parentFiber.child; while (child !== null) { - setCurrentDebugFiberInDEV(child); const current = child.alternate; - commitLayoutEffectOnFiber(root, current, child, lanes); + if (__DEV__) { + runWithFiberInDEV( + child, + commitLayoutEffectOnFiber, + root, + current, + child, + lanes, + ); + } else { + commitLayoutEffectOnFiber(root, current, child, lanes); + } child = child.sibling; } } - setCurrentDebugFiberInDEV(prevDebugFiber); } export function disappearLayoutEffects(finishedWork: Fiber) { @@ -3386,19 +3408,28 @@ function recursivelyTraverseReappearLayoutEffects( (parentFiber.subtreeFlags & LayoutMask) !== NoFlags; // TODO (Offscreen) Check: flags & (RefStatic | LayoutStatic) - const prevDebugFiber = getCurrentDebugFiberInDEV(); let child = parentFiber.child; while (child !== null) { const current = child.alternate; - reappearLayoutEffects( - finishedRoot, - current, - child, - childShouldIncludeWorkInProgressEffects, - ); + if (__DEV__) { + runWithFiberInDEV( + child, + reappearLayoutEffects, + finishedRoot, + current, + child, + childShouldIncludeWorkInProgressEffects, + ); + } else { + reappearLayoutEffects( + finishedRoot, + current, + child, + childShouldIncludeWorkInProgressEffects, + ); + } child = child.sibling; } - setCurrentDebugFiberInDEV(prevDebugFiber); } function commitHookPassiveMountEffects( @@ -3568,14 +3599,23 @@ export function commitPassiveMountEffects( committedLanes: Lanes, committedTransitions: Array | null, ): void { - setCurrentDebugFiberInDEV(finishedWork); - commitPassiveMountOnFiber( - root, - finishedWork, - committedLanes, - committedTransitions, - ); - resetCurrentDebugFiberInDEV(); + if (__DEV__) { + runWithFiberInDEV( + finishedWork, + commitPassiveMountOnFiber, + root, + finishedWork, + committedLanes, + committedTransitions, + ); + } else { + commitPassiveMountOnFiber( + root, + finishedWork, + committedLanes, + committedTransitions, + ); + } } function recursivelyTraversePassiveMountEffects( @@ -3584,21 +3624,29 @@ function recursivelyTraversePassiveMountEffects( committedLanes: Lanes, committedTransitions: Array | null, ) { - const prevDebugFiber = getCurrentDebugFiberInDEV(); if (parentFiber.subtreeFlags & PassiveMask) { let child = parentFiber.child; while (child !== null) { - setCurrentDebugFiberInDEV(child); - commitPassiveMountOnFiber( - root, - child, - committedLanes, - committedTransitions, - ); + if (__DEV__) { + runWithFiberInDEV( + child, + commitPassiveMountOnFiber, + root, + child, + committedLanes, + committedTransitions, + ); + } else { + commitPassiveMountOnFiber( + root, + child, + committedLanes, + committedTransitions, + ); + } child = child.sibling; } } - setCurrentDebugFiberInDEV(prevDebugFiber); } function commitPassiveMountOnFiber( @@ -3835,19 +3883,29 @@ function recursivelyTraverseReconnectPassiveEffects( (parentFiber.subtreeFlags & PassiveMask) !== NoFlags; // TODO (Offscreen) Check: flags & (RefStatic | LayoutStatic) - const prevDebugFiber = getCurrentDebugFiberInDEV(); let child = parentFiber.child; while (child !== null) { - reconnectPassiveEffects( - finishedRoot, - child, - committedLanes, - committedTransitions, - childShouldIncludeWorkInProgressEffects, - ); + if (__DEV__) { + runWithFiberInDEV( + child, + reconnectPassiveEffects, + finishedRoot, + child, + committedLanes, + committedTransitions, + childShouldIncludeWorkInProgressEffects, + ); + } else { + reconnectPassiveEffects( + finishedRoot, + child, + committedLanes, + committedTransitions, + childShouldIncludeWorkInProgressEffects, + ); + } child = child.sibling; } - setCurrentDebugFiberInDEV(prevDebugFiber); } export function reconnectPassiveEffects( @@ -4023,22 +4081,30 @@ function recursivelyTraverseAtomicPassiveEffects( // "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. - const prevDebugFiber = getCurrentDebugFiberInDEV(); // TODO: Add special flag for atomic effects if (parentFiber.subtreeFlags & PassiveMask) { let child = parentFiber.child; while (child !== null) { - setCurrentDebugFiberInDEV(child); - commitAtomicPassiveEffects( - finishedRoot, - child, - committedLanes, - committedTransitions, - ); + if (__DEV__) { + runWithFiberInDEV( + child, + commitAtomicPassiveEffects, + finishedRoot, + child, + committedLanes, + committedTransitions, + ); + } else { + commitAtomicPassiveEffects( + finishedRoot, + child, + committedLanes, + committedTransitions, + ); + } child = child.sibling; } } - setCurrentDebugFiberInDEV(prevDebugFiber); } function commitAtomicPassiveEffects( @@ -4094,9 +4160,11 @@ function commitAtomicPassiveEffects( } export function commitPassiveUnmountEffects(finishedWork: Fiber): void { - setCurrentDebugFiberInDEV(finishedWork); - commitPassiveUnmountOnFiber(finishedWork); - resetCurrentDebugFiberInDEV(); + if (__DEV__) { + runWithFiberInDEV(finishedWork, commitPassiveUnmountOnFiber, finishedWork); + } else { + commitPassiveUnmountOnFiber(finishedWork); + } } // If we're inside a brand new tree, or a tree that was already visible, then we @@ -4265,17 +4333,18 @@ function recursivelyTraversePassiveUnmountEffects(parentFiber: Fiber): void { detachAlternateSiblings(parentFiber); } - const prevDebugFiber = getCurrentDebugFiberInDEV(); // TODO: Split PassiveMask into separate masks for mount and unmount? if (parentFiber.subtreeFlags & PassiveMask) { let child = parentFiber.child; while (child !== null) { - setCurrentDebugFiberInDEV(child); - commitPassiveUnmountOnFiber(child); + if (__DEV__) { + runWithFiberInDEV(child, commitPassiveUnmountOnFiber, child); + } else { + commitPassiveUnmountOnFiber(child); + } child = child.sibling; } } - setCurrentDebugFiberInDEV(prevDebugFiber); } function commitPassiveUnmountOnFiber(finishedWork: Fiber): void { @@ -4346,15 +4415,16 @@ function recursivelyTraverseDisconnectPassiveEffects(parentFiber: Fiber): void { detachAlternateSiblings(parentFiber); } - const prevDebugFiber = getCurrentDebugFiberInDEV(); // TODO: Check PassiveStatic flag let child = parentFiber.child; while (child !== null) { - setCurrentDebugFiberInDEV(child); - disconnectPassiveEffect(child); + if (__DEV__) { + runWithFiberInDEV(child, disconnectPassiveEffect, child); + } else { + disconnectPassiveEffect(child); + } child = child.sibling; } - setCurrentDebugFiberInDEV(prevDebugFiber); } export function disconnectPassiveEffect(finishedWork: Fiber): void { @@ -4399,9 +4469,19 @@ function commitPassiveUnmountEffectsInsideOfDeletedTree_begin( // Deletion effects fire in parent -> child order // TODO: Check if fiber has a PassiveStatic flag - setCurrentDebugFiberInDEV(fiber); - commitPassiveUnmountInsideDeletedTreeOnFiber(fiber, nearestMountedAncestor); - resetCurrentDebugFiberInDEV(); + if (__DEV__) { + runWithFiberInDEV( + fiber, + commitPassiveUnmountInsideDeletedTreeOnFiber, + fiber, + nearestMountedAncestor, + ); + } else { + commitPassiveUnmountInsideDeletedTreeOnFiber( + fiber, + nearestMountedAncestor, + ); + } const child = fiber.child; // TODO: Only traverse subtree if it has a PassiveStatic flag. diff --git a/packages/react-reconciler/src/ReactFiberReconciler.js b/packages/react-reconciler/src/ReactFiberReconciler.js index eb1bfbb65a6cf..4d793f9c60876 100644 --- a/packages/react-reconciler/src/ReactFiberReconciler.js +++ b/packages/react-reconciler/src/ReactFiberReconciler.js @@ -78,8 +78,7 @@ import { import { isRendering as ReactCurrentFiberIsRendering, current as ReactCurrentFiberCurrent, - resetCurrentDebugFiberInDEV, - setCurrentDebugFiberInDEV, + runWithFiberInDEV, } from './ReactCurrentFiber'; import {StrictLegacyMode} from './ReactTypeOfMode'; import { @@ -202,10 +201,7 @@ function findHostInstanceWithWarning( const componentName = getComponentNameFromFiber(fiber) || 'Component'; if (!didWarnAboutFindNodeInStrictMode[componentName]) { didWarnAboutFindNodeInStrictMode[componentName] = true; - - const previousFiber = ReactCurrentFiberCurrent; - try { - setCurrentDebugFiberInDEV(hostFiber); + runWithFiberInDEV(hostFiber, () => { if (fiber.mode & StrictLegacyMode) { console.error( '%s is deprecated in StrictMode. ' + @@ -229,15 +225,7 @@ function findHostInstanceWithWarning( componentName, ); } - } finally { - // Ideally this should reset to previous but this shouldn't be called in - // render and there's another warning for that anyway. - if (previousFiber) { - setCurrentDebugFiberInDEV(previousFiber); - } else { - resetCurrentDebugFiberInDEV(); - } - } + }); } } return getPublicInstance(hostFiber.stateNode); diff --git a/packages/react-reconciler/src/ReactFiberThrow.js b/packages/react-reconciler/src/ReactFiberThrow.js index 40a68b1c047b0..cf91f0e68a68b 100644 --- a/packages/react-reconciler/src/ReactFiberThrow.js +++ b/packages/react-reconciler/src/ReactFiberThrow.js @@ -87,10 +87,7 @@ import { import {ConcurrentRoot} from './ReactRootTags'; import {noopSuspenseyCommitThenable} from './ReactFiberThenable'; import {REACT_POSTPONE_TYPE} from 'shared/ReactSymbols'; -import { - setCurrentDebugFiberInDEV, - getCurrentFiber as getCurrentDebugFiberInDEV, -} from './ReactCurrentFiber'; +import {runWithFiberInDEV} from './ReactCurrentFiber'; function createRootErrorUpdate( root: FiberRoot, @@ -104,10 +101,11 @@ function createRootErrorUpdate( // being called "element". update.payload = {element: null}; update.callback = () => { - const prevFiber = getCurrentDebugFiberInDEV(); // should just be the root - setCurrentDebugFiberInDEV(errorInfo.source); - logUncaughtError(root, errorInfo); - setCurrentDebugFiberInDEV(prevFiber); + if (__DEV__) { + runWithFiberInDEV(errorInfo.source, logUncaughtError, root, errorInfo); + } else { + logUncaughtError(root, errorInfo); + } }; return update; } @@ -134,10 +132,17 @@ function initializeClassErrorUpdate( if (__DEV__) { markFailedErrorBoundaryForHotReloading(fiber); } - const prevFiber = getCurrentDebugFiberInDEV(); // should be the error boundary - setCurrentDebugFiberInDEV(errorInfo.source); - logCaughtError(root, fiber, errorInfo); - setCurrentDebugFiberInDEV(prevFiber); + if (__DEV__) { + runWithFiberInDEV( + errorInfo.source, + logCaughtError, + root, + fiber, + errorInfo, + ); + } else { + logCaughtError(root, fiber, errorInfo); + } }; } @@ -148,10 +153,17 @@ function initializeClassErrorUpdate( if (__DEV__) { markFailedErrorBoundaryForHotReloading(fiber); } - const prevFiber = getCurrentDebugFiberInDEV(); // should be the error boundary - setCurrentDebugFiberInDEV(errorInfo.source); - logCaughtError(root, fiber, errorInfo); - setCurrentDebugFiberInDEV(prevFiber); + if (__DEV__) { + runWithFiberInDEV( + errorInfo.source, + logCaughtError, + root, + fiber, + errorInfo, + ); + } else { + logCaughtError(root, fiber, errorInfo); + } if (typeof getDerivedStateFromError !== 'function') { // To preserve the preexisting retry behavior of error boundaries, // we keep track of which ones already failed during this batch. diff --git a/packages/react-reconciler/src/ReactFiberWorkLoop.js b/packages/react-reconciler/src/ReactFiberWorkLoop.js index 1529cef24afdd..febd5da675ea2 100644 --- a/packages/react-reconciler/src/ReactFiberWorkLoop.js +++ b/packages/react-reconciler/src/ReactFiberWorkLoop.js @@ -230,10 +230,8 @@ import getComponentNameFromFiber from 'react-reconciler/src/getComponentNameFrom import ReactStrictModeWarnings from './ReactStrictModeWarnings'; import { isRendering as ReactCurrentDebugFiberIsRenderingInDEV, - current as ReactCurrentFiberCurrent, - resetCurrentDebugFiberInDEV, - setCurrentDebugFiberInDEV, resetCurrentFiber, + runWithFiberInDEV, } from './ReactCurrentFiber'; import { isDevToolsPresent, @@ -2374,18 +2372,37 @@ function performUnitOfWork(unitOfWork: Fiber): void { // nothing should rely on this, but relying on it here means that we don't // need an additional field on the work in progress. const current = unitOfWork.alternate; - setCurrentDebugFiberInDEV(unitOfWork); let next; if (enableProfilerTimer && (unitOfWork.mode & ProfileMode) !== NoMode) { startProfilerTimer(unitOfWork); - next = beginWork(current, unitOfWork, entangledRenderLanes); + if (__DEV__) { + next = runWithFiberInDEV( + unitOfWork, + beginWork, + current, + unitOfWork, + entangledRenderLanes, + ); + } else { + next = beginWork(current, unitOfWork, entangledRenderLanes); + } stopProfilerTimerIfRunningAndRecordDelta(unitOfWork, true); } else { - next = beginWork(current, unitOfWork, entangledRenderLanes); + if (__DEV__) { + next = runWithFiberInDEV( + unitOfWork, + beginWork, + current, + unitOfWork, + entangledRenderLanes, + ); + } else { + next = beginWork(current, unitOfWork, entangledRenderLanes); + } } - if (__DEV__ || !disableStringRefs) { + if (!disableStringRefs) { resetCurrentFiber(); } unitOfWork.memoizedProps = unitOfWork.pendingProps; @@ -2400,9 +2417,32 @@ function performUnitOfWork(unitOfWork: Fiber): void { function replaySuspendedUnitOfWork(unitOfWork: Fiber): void { // This is a fork of performUnitOfWork specifcally for replaying a fiber that // just suspended. - // + let next; + if (__DEV__) { + next = runWithFiberInDEV(unitOfWork, replayBeginWork, unitOfWork); + } else { + next = replayBeginWork(unitOfWork); + } + + // The begin phase finished successfully without suspending. Return to the + // normal work loop. + if (!disableStringRefs) { + resetCurrentFiber(); + } + unitOfWork.memoizedProps = unitOfWork.pendingProps; + if (next === null) { + // If this doesn't spawn new work, complete the current work. + completeUnitOfWork(unitOfWork); + } else { + workInProgress = next; + } +} + +function replayBeginWork(unitOfWork: Fiber): null | Fiber { + // This is a fork of beginWork specifcally for replaying a fiber that + // just suspended. + const current = unitOfWork.alternate; - setCurrentDebugFiberInDEV(unitOfWork); let next; const isProfilingMode = @@ -2494,19 +2534,7 @@ function replaySuspendedUnitOfWork(unitOfWork: Fiber): void { stopProfilerTimerIfRunningAndRecordDelta(unitOfWork, true); } - // The begin phase finished successfully without suspending. Return to the - // normal work loop. - - if (__DEV__ || !disableStringRefs) { - resetCurrentFiber(); - } - unitOfWork.memoizedProps = unitOfWork.pendingProps; - if (next === null) { - // If this doesn't spawn new work, complete the current work. - completeUnitOfWork(unitOfWork); - } else { - workInProgress = next; - } + return next; } function throwAndUnwindWorkLoop( @@ -2605,17 +2633,35 @@ function completeUnitOfWork(unitOfWork: Fiber): void { const current = completedWork.alternate; const returnFiber = completedWork.return; - setCurrentDebugFiberInDEV(completedWork); let next; if (!enableProfilerTimer || (completedWork.mode & ProfileMode) === NoMode) { - next = completeWork(current, completedWork, entangledRenderLanes); + if (__DEV__) { + next = runWithFiberInDEV( + completedWork, + completeWork, + current, + completedWork, + entangledRenderLanes, + ); + } else { + next = completeWork(current, completedWork, entangledRenderLanes); + } } else { startProfilerTimer(completedWork); - next = completeWork(current, completedWork, entangledRenderLanes); + if (__DEV__) { + next = runWithFiberInDEV( + completedWork, + completeWork, + current, + completedWork, + entangledRenderLanes, + ); + } else { + next = completeWork(current, completedWork, entangledRenderLanes); + } // Update render duration assuming we didn't error. stopProfilerTimerIfRunningAndRecordDelta(completedWork, false); } - resetCurrentDebugFiberInDEV(); if (next !== null) { // Completing this fiber spawned new work. Work on that next. @@ -3038,9 +3084,16 @@ function commitRootImpl( for (let i = 0; i < recoverableErrors.length; i++) { const recoverableError = recoverableErrors[i]; const errorInfo = makeErrorInfo(recoverableError.stack); - setCurrentDebugFiberInDEV(recoverableError.source); - onRecoverableError(recoverableError.value, errorInfo); - resetCurrentDebugFiberInDEV(); + if (__DEV__) { + runWithFiberInDEV( + recoverableError.source, + onRecoverableError, + recoverableError.value, + errorInfo, + ); + } else { + onRecoverableError(recoverableError.value, errorInfo); + } } } @@ -3691,15 +3744,15 @@ function doubleInvokeEffectsInDEVIfNecessary( // special rules apply to double invoking effects. if (fiber.tag !== OffscreenComponent) { if (fiber.flags & PlacementDEV) { - setCurrentDebugFiberInDEV(fiber); if (isInStrictMode) { - doubleInvokeEffectsOnFiber( + runWithFiberInDEV( + fiber, + doubleInvokeEffectsOnFiber, root, fiber, (fiber.mode & NoStrictPassiveEffectsMode) === NoMode, ); } - resetCurrentDebugFiberInDEV(); } else { recursivelyTraverseAndDoubleInvokeEffectsInDEV( root, @@ -3715,21 +3768,21 @@ function doubleInvokeEffectsInDEVIfNecessary( if (fiber.memoizedState === null) { // Only consider Offscreen that is visible. // TODO (Offscreen) Handle manual mode. - setCurrentDebugFiberInDEV(fiber); if (isInStrictMode && fiber.flags & Visibility) { // Double invoke effects on Offscreen's subtree only // if it is visible and its visibility has changed. - doubleInvokeEffectsOnFiber(root, fiber); + runWithFiberInDEV(fiber, doubleInvokeEffectsOnFiber, root, fiber); } else if (fiber.subtreeFlags & PlacementDEV) { // Something in the subtree could have been suspended. // We need to continue traversal and find newly inserted fibers. - recursivelyTraverseAndDoubleInvokeEffectsInDEV( + runWithFiberInDEV( + fiber, + recursivelyTraverseAndDoubleInvokeEffectsInDEV, root, fiber, isInStrictMode, ); } - resetCurrentDebugFiberInDEV(); } } @@ -3753,7 +3806,13 @@ function commitDoubleInvokeEffectsInDEV( doubleInvokeEffects, ); } else { - legacyCommitDoubleInvokeEffectsInDEV(root.current, hasPassiveEffects); + // TODO: Is this runWithFiberInDEV needed since the other effect functions do it too? + runWithFiberInDEV( + root.current, + legacyCommitDoubleInvokeEffectsInDEV, + root.current, + hasPassiveEffects, + ); } } } @@ -3766,7 +3825,6 @@ function legacyCommitDoubleInvokeEffectsInDEV( // so we don't traverse unnecessarily? similar to subtreeFlags but just at the root level. // Maybe not a big deal since this is DEV only behavior. - setCurrentDebugFiberInDEV(fiber); invokeEffectsInDev(fiber, MountLayoutDev, invokeLayoutEffectUnmountInDEV); if (hasPassiveEffects) { invokeEffectsInDev(fiber, MountPassiveDev, invokePassiveEffectUnmountInDEV); @@ -3776,7 +3834,6 @@ function legacyCommitDoubleInvokeEffectsInDEV( if (hasPassiveEffects) { invokeEffectsInDev(fiber, MountPassiveDev, invokePassiveEffectMountInDEV); } - resetCurrentDebugFiberInDEV(); } function invokeEffectsInDev( @@ -3846,22 +3903,14 @@ export function warnAboutUpdateOnNotYetMountedFiberInDEV(fiber: Fiber) { didWarnStateUpdateForNotYetMountedComponent = new Set([componentName]); } - const previousFiber = ReactCurrentFiberCurrent; - try { - setCurrentDebugFiberInDEV(fiber); + runWithFiberInDEV(fiber, () => { console.error( "Can't perform a React state update on a component that hasn't mounted yet. " + 'This indicates that you have a side-effect in your render function that ' + 'asynchronously later calls tries to update the component. Move this work to ' + 'useEffect instead.', ); - } finally { - if (previousFiber) { - setCurrentDebugFiberInDEV(fiber); - } else { - resetCurrentDebugFiberInDEV(); - } - } + }); } } @@ -3983,9 +4032,7 @@ function warnIfUpdatesNotWrappedWithActDEV(fiber: Fiber): void { } if (ReactSharedInternals.actQueue === null) { - const previousFiber = ReactCurrentFiberCurrent; - try { - setCurrentDebugFiberInDEV(fiber); + runWithFiberInDEV(fiber, () => { console.error( 'An update to %s inside a test was not wrapped in act(...).\n\n' + 'When testing, code that causes React state updates should be ' + @@ -3999,13 +4046,7 @@ function warnIfUpdatesNotWrappedWithActDEV(fiber: Fiber): void { ' Learn more at https://react.dev/link/wrap-tests-with-act', getComponentNameFromFiber(fiber), ); - } finally { - if (previousFiber) { - setCurrentDebugFiberInDEV(fiber); - } else { - resetCurrentDebugFiberInDEV(); - } - } + }); } } } diff --git a/packages/react-reconciler/src/ReactStrictModeWarnings.js b/packages/react-reconciler/src/ReactStrictModeWarnings.js index d14a38a9020be..99a37206ed539 100644 --- a/packages/react-reconciler/src/ReactStrictModeWarnings.js +++ b/packages/react-reconciler/src/ReactStrictModeWarnings.js @@ -9,10 +9,7 @@ import type {Fiber} from './ReactInternalTypes'; -import { - resetCurrentDebugFiberInDEV, - setCurrentDebugFiberInDEV, -} from './ReactCurrentFiber'; +import {runWithFiberInDEV} from './ReactCurrentFiber'; import getComponentNameFromFiber from 'react-reconciler/src/getComponentNameFromFiber'; import {StrictLegacyMode} from './ReactTypeOfMode'; @@ -339,8 +336,7 @@ if (__DEV__) { const sortedNames = setToSortedString(uniqueNames); - try { - setCurrentDebugFiberInDEV(firstFiber); + runWithFiberInDEV(firstFiber, () => { console.error( 'Legacy context API has been detected within a strict-mode tree.' + '\n\nThe old API will be supported in all 16.x releases, but applications ' + @@ -349,9 +345,7 @@ if (__DEV__) { '\n\nLearn more about this warning here: https://react.dev/link/legacy-context', sortedNames, ); - } finally { - resetCurrentDebugFiberInDEV(); - } + }); }, ); };