diff --git a/packages/react-reconciler/src/ReactChildFiber.js b/packages/react-reconciler/src/ReactChildFiber.js index 3346c739536d..0220f988c15d 100644 --- a/packages/react-reconciler/src/ReactChildFiber.js +++ b/packages/react-reconciler/src/ReactChildFiber.js @@ -63,10 +63,7 @@ import {createThenableState, trackUsedThenable} from './ReactFiberThenable'; import {readContextDuringReconciliation} from './ReactFiberNewContext'; import {callLazyInitInDEV} from './ReactFiberCallUserSpace'; -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; @@ -182,15 +179,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, + ); + }); }; } @@ -213,14 +209,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; } } @@ -232,10 +231,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 fa2a11c00a8d..98e82247d589 100644 --- a/packages/react-reconciler/src/ReactCurrentFiber.js +++ b/packages/react-reconciler/src/ReactCurrentFiber.js @@ -61,16 +61,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() { @@ -90,13 +103,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 5c7f845b9679..a8d37b5e4493 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 eb1bfbb65a6c..4d793f9c6087 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 40a68b1c047b..cf91f0e68a68 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 6121c48a71fc..b10be76de1a9 100644 --- a/packages/react-reconciler/src/ReactFiberWorkLoop.js +++ b/packages/react-reconciler/src/ReactFiberWorkLoop.js @@ -231,10 +231,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, @@ -2381,18 +2379,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; @@ -2407,9 +2424,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 = @@ -2501,19 +2541,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( @@ -2612,17 +2640,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. @@ -3045,9 +3091,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); + } } } @@ -3698,15 +3751,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, @@ -3722,21 +3775,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(); } } @@ -3760,7 +3813,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, + ); } } } @@ -3773,7 +3832,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); @@ -3783,7 +3841,6 @@ function legacyCommitDoubleInvokeEffectsInDEV( if (hasPassiveEffects) { invokeEffectsInDev(fiber, MountPassiveDev, invokePassiveEffectMountInDEV); } - resetCurrentDebugFiberInDEV(); } function invokeEffectsInDev( @@ -3853,22 +3910,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(); - } - } + }); } } @@ -3990,9 +4039,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 ' + @@ -4006,13 +4053,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 d14a38a9020b..99a37206ed53 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(); - } + }); }, ); };