@samitouri / QOS-React-2 / commits / b078c810c7

[Fiber] Replace setCurrentDebugFiberInDEV with runWithFiberInDEV (#29221)

Stacked on #29044. To work with `console.createTask(...).run(...)` we need to be able to run a function in the scope of the task. The main concern with this, other than general performance, is that it might add more stack frames on very deep stacks that hit the stack limit. Such as with the commit phase where we recursively go down the tree. These callbacks aren't really necessary in the recursive part but only in the shallow invocation of the commit phase for each tag. So we could refactor the commit phase so that only the shallow part at each level is covered this way.

Sebastian Markbåge committed May 25, 2024 at 11:58 UTC b078c810c787cf13d9bd1958f083b4e3a162a720
7 files changed +342 -223
packages/react-reconciler/src/ReactChildFiber.js
+21 -23
@@ -63,10 +63,7 @@ import {createThenableState, trackUsedThenable} from './ReactFiberThenable';
63 import {readContextDuringReconciliation} from './ReactFiberNewContext';
64 import {callLazyInitInDEV} from './ReactFiberCallUserSpace';
65
66 -import {
67 - getCurrentFiber as getCurrentDebugFiberInDEV,
68 - setCurrentFiber as setCurrentDebugFiberInDEV,
69 -} from './ReactCurrentFiber';
66 +import {runWithFiberInDEV} from './ReactCurrentFiber';
67
68 // This tracks the thenables that are unwrapped during reconcilation.
69 let thenableState: ThenableState | null = null;
@@ -182,15 +179,14 @@ if (__DEV__) {
179 const fiber = createFiberFromElement((child: any), returnFiber.mode, 0);
180 fiber.return = returnFiber;
181
185 - const prevDebugFiber = getCurrentDebugFiberInDEV();
186 - setCurrentDebugFiberInDEV(fiber);
187 - console.error(
188 - 'Each child in a list should have a unique "key" prop.' +
189 - '%s%s See https://react.dev/link/warning-keys for more information.',
190 - currentComponentErrorInfo,
191 - childOwnerAppendix,
192 - );
193 - setCurrentDebugFiberInDEV(prevDebugFiber);
182 + runWithFiberInDEV(fiber, () => {
183 + console.error(
184 + 'Each child in a list should have a unique "key" prop.' +
185 + '%s%s See https://react.dev/link/warning-keys for more information.',
186 + currentComponentErrorInfo,
187 + childOwnerAppendix,
188 + );
189 + });
190 };
191 }
192
@@ -213,14 +209,17 @@ function validateFragmentProps(
209 fiber = createFiberFromElement(element, returnFiber.mode, 0);
210 fiber.return = returnFiber;
211 }
216 - const prevDebugFiber = getCurrentDebugFiberInDEV();
217 - setCurrentDebugFiberInDEV(fiber);
218 - console.error(
219 - 'Invalid prop `%s` supplied to `React.Fragment`. ' +
220 - 'React.Fragment can only have `key` and `children` props.',
212 + runWithFiberInDEV(
213 + fiber,
214 + erroredKey => {
215 + console.error(
216 + 'Invalid prop `%s` supplied to `React.Fragment`. ' +
217 + 'React.Fragment can only have `key` and `children` props.',
218 + erroredKey,
219 + );
220 + },
221 key,
222 );
223 - setCurrentDebugFiberInDEV(prevDebugFiber);
223 break;
224 }
225 }
@@ -232,10 +231,9 @@ function validateFragmentProps(
231 fiber = createFiberFromElement(element, returnFiber.mode, 0);
232 fiber.return = returnFiber;
233 }
235 - const prevDebugFiber = getCurrentDebugFiberInDEV();
236 - setCurrentDebugFiberInDEV(fiber);
237 - console.error('Invalid attribute `ref` supplied to `React.Fragment`.');
238 - setCurrentDebugFiberInDEV(prevDebugFiber);
234 + runWithFiberInDEV(fiber, () => {
235 + console.error('Invalid attribute `ref` supplied to `React.Fragment`.');
236 + });
237 }
238 }
239 }
packages/react-reconciler/src/ReactCurrentFiber.js
+20 -14
@@ -61,16 +61,29 @@ function getCurrentFiberStackInDev(): string {
61 return '';
62 }
63
64 -export function resetCurrentDebugFiberInDEV() {
65 - if (__DEV__) {
66 - resetCurrentFiber();
67 - }
68 -}
69 -
70 -export function setCurrentDebugFiberInDEV(fiber: Fiber | null) {
64 +export function runWithFiberInDEV<A0, A1, A2, A3, A4, T>(
65 + fiber: null | Fiber,
66 + callback: (A0, A1, A2, A3, A4) => T,
67 + arg0: A0,
68 + arg1: A1,
69 + arg2: A2,
70 + arg3: A3,
71 + arg4: A4,
72 +): T {
73 if (__DEV__) {
74 + const previousFiber = current;
75 setCurrentFiber(fiber);
76 + try {
77 + return callback(arg0, arg1, arg2, arg3, arg4);
78 + } finally {
79 + current = previousFiber;
80 + }
81 }
82 + // These errors should never make it into a build so we don't need to encode them in codes.json
83 + // eslint-disable-next-line react-internal/prod-error-codes
84 + throw new Error(
85 + 'runWithFiberInDEV should never be called in production. This is a bug in React.',
86 + );
87 }
88
89 export function resetCurrentFiber() {
@@ -90,13 +103,6 @@ export function setCurrentFiber(fiber: Fiber | null) {
103 current = fiber;
104 }
105
93 -export function getCurrentFiber(): Fiber | null {
94 - if (__DEV__) {
95 - return current;
96 - }
97 - return null;
98 -}
99 -
106 export function setIsRendering(rendering: boolean) {
107 if (__DEV__) {
108 isRendering = rendering;
packages/react-reconciler/src/ReactFiberCommitWork.js
+167 -87
@@ -100,11 +100,7 @@ import {
100 FormReset,
101 } from './ReactFiberFlags';
102 import getComponentNameFromFiber from 'react-reconciler/src/getComponentNameFromFiber';
103 -import {
104 - resetCurrentDebugFiberInDEV,
105 - setCurrentDebugFiberInDEV,
106 - getCurrentFiber as getCurrentDebugFiberInDEV,
107 -} from './ReactCurrentFiber';
103 +import {runWithFiberInDEV} from './ReactCurrentFiber';
104 import {resolveClassComponentProps} from './ReactFiberClassComponent';
105 import {
106 isCurrentUpdateNested,
@@ -403,13 +399,15 @@ function commitBeforeMutationEffects_begin() {
399 function commitBeforeMutationEffects_complete() {
400 while (nextEffect !== null) {
401 const fiber = nextEffect;
406 - setCurrentDebugFiberInDEV(fiber);
402 try {
408 - commitBeforeMutationEffectsOnFiber(fiber);
403 + if (__DEV__) {
404 + runWithFiberInDEV(fiber, commitBeforeMutationEffectsOnFiber, fiber);
405 + } else {
406 + commitBeforeMutationEffectsOnFiber(fiber);
407 + }
408 } catch (error) {
409 captureCommitPhaseError(fiber, fiber.return, error);
410 }
412 - resetCurrentDebugFiberInDEV();
411
412 const sibling = fiber.sibling;
413 if (sibling !== null) {
@@ -442,10 +440,6 @@ function commitBeforeMutationEffectsOnFiber(finishedWork: Fiber) {
440 }
441 }
442
445 - if ((flags & Snapshot) !== NoFlags) {
446 - setCurrentDebugFiberInDEV(finishedWork);
447 - }
448 -
443 switch (finishedWork.tag) {
444 case FunctionComponent: {
445 if (enableUseEffectEventHook) {
@@ -547,10 +541,6 @@ function commitBeforeMutationEffectsOnFiber(finishedWork: Fiber) {
541 }
542 }
543 }
550 -
551 - if ((flags & Snapshot) !== NoFlags) {
552 - resetCurrentDebugFiberInDEV();
553 - }
544 }
545
546 function commitBeforeMutationEffectsDeletion(deletion: Fiber) {
@@ -2484,9 +2474,17 @@ export function commitMutationEffects(
2474 inProgressLanes = committedLanes;
2475 inProgressRoot = root;
2476
2487 - setCurrentDebugFiberInDEV(finishedWork);
2488 - commitMutationEffectsOnFiber(finishedWork, root, committedLanes);
2489 - resetCurrentDebugFiberInDEV();
2477 + if (__DEV__) {
2478 + runWithFiberInDEV(
2479 + finishedWork,
2480 + commitMutationEffectsOnFiber,
2481 + finishedWork,
2482 + root,
2483 + committedLanes,
2484 + );
2485 + } else {
2486 + commitMutationEffectsOnFiber(finishedWork, root, committedLanes);
2487 + }
2488
2489 inProgressLanes = null;
2490 inProgressRoot = null;
@@ -2511,16 +2509,23 @@ function recursivelyTraverseMutationEffects(
2509 }
2510 }
2511
2514 - const prevDebugFiber = getCurrentDebugFiberInDEV();
2512 if (parentFiber.subtreeFlags & MutationMask) {
2513 let child = parentFiber.child;
2514 while (child !== null) {
2518 - setCurrentDebugFiberInDEV(child);
2519 - commitMutationEffectsOnFiber(child, root, lanes);
2515 + if (__DEV__) {
2516 + runWithFiberInDEV(
2517 + child,
2518 + commitMutationEffectsOnFiber,
2519 + child,
2520 + root,
2521 + lanes,
2522 + );
2523 + } else {
2524 + commitMutationEffectsOnFiber(child, root, lanes);
2525 + }
2526 child = child.sibling;
2527 }
2528 }
2523 - setCurrentDebugFiberInDEV(prevDebugFiber);
2529 }
2530
2531 let currentHoistableRoot: HoistableRoot | null = null;
@@ -3125,10 +3130,19 @@ export function commitLayoutEffects(
3130 inProgressLanes = committedLanes;
3131 inProgressRoot = root;
3132
3128 - setCurrentDebugFiberInDEV(finishedWork);
3133 const current = finishedWork.alternate;
3130 - commitLayoutEffectOnFiber(root, current, finishedWork, committedLanes);
3131 - resetCurrentDebugFiberInDEV();
3134 + if (__DEV__) {
3135 + runWithFiberInDEV(
3136 + finishedWork,
3137 + commitLayoutEffectOnFiber,
3138 + root,
3139 + current,
3140 + finishedWork,
3141 + committedLanes,
3142 + );
3143 + } else {
3144 + commitLayoutEffectOnFiber(root, current, finishedWork, committedLanes);
3145 + }
3146
3147 inProgressLanes = null;
3148 inProgressRoot = null;
@@ -3139,17 +3153,25 @@ function recursivelyTraverseLayoutEffects(
3153 parentFiber: Fiber,
3154 lanes: Lanes,
3155 ) {
3142 - const prevDebugFiber = getCurrentDebugFiberInDEV();
3156 if (parentFiber.subtreeFlags & LayoutMask) {
3157 let child = parentFiber.child;
3158 while (child !== null) {
3146 - setCurrentDebugFiberInDEV(child);
3159 const current = child.alternate;
3148 - commitLayoutEffectOnFiber(root, current, child, lanes);
3160 + if (__DEV__) {
3161 + runWithFiberInDEV(
3162 + child,
3163 + commitLayoutEffectOnFiber,
3164 + root,
3165 + current,
3166 + child,
3167 + lanes,
3168 + );
3169 + } else {
3170 + commitLayoutEffectOnFiber(root, current, child, lanes);
3171 + }
3172 child = child.sibling;
3173 }
3174 }
3152 - setCurrentDebugFiberInDEV(prevDebugFiber);
3175 }
3176
3177 export function disappearLayoutEffects(finishedWork: Fiber) {
@@ -3386,19 +3408,28 @@ function recursivelyTraverseReappearLayoutEffects(
3408 (parentFiber.subtreeFlags & LayoutMask) !== NoFlags;
3409
3410 // TODO (Offscreen) Check: flags & (RefStatic | LayoutStatic)
3389 - const prevDebugFiber = getCurrentDebugFiberInDEV();
3411 let child = parentFiber.child;
3412 while (child !== null) {
3413 const current = child.alternate;
3393 - reappearLayoutEffects(
3394 - finishedRoot,
3395 - current,
3396 - child,
3397 - childShouldIncludeWorkInProgressEffects,
3398 - );
3414 + if (__DEV__) {
3415 + runWithFiberInDEV(
3416 + child,
3417 + reappearLayoutEffects,
3418 + finishedRoot,
3419 + current,
3420 + child,
3421 + childShouldIncludeWorkInProgressEffects,
3422 + );
3423 + } else {
3424 + reappearLayoutEffects(
3425 + finishedRoot,
3426 + current,
3427 + child,
3428 + childShouldIncludeWorkInProgressEffects,
3429 + );
3430 + }
3431 child = child.sibling;
3432 }
3401 - setCurrentDebugFiberInDEV(prevDebugFiber);
3433 }
3434
3435 function commitHookPassiveMountEffects(
@@ -3568,14 +3599,23 @@ export function commitPassiveMountEffects(
3599 committedLanes: Lanes,
3600 committedTransitions: Array<Transition> | null,
3601 ): void {
3571 - setCurrentDebugFiberInDEV(finishedWork);
3572 - commitPassiveMountOnFiber(
3573 - root,
3574 - finishedWork,
3575 - committedLanes,
3576 - committedTransitions,
3577 - );
3578 - resetCurrentDebugFiberInDEV();
3602 + if (__DEV__) {
3603 + runWithFiberInDEV(
3604 + finishedWork,
3605 + commitPassiveMountOnFiber,
3606 + root,
3607 + finishedWork,
3608 + committedLanes,
3609 + committedTransitions,
3610 + );
3611 + } else {
3612 + commitPassiveMountOnFiber(
3613 + root,
3614 + finishedWork,
3615 + committedLanes,
3616 + committedTransitions,
3617 + );
3618 + }
3619 }
3620
3621 function recursivelyTraversePassiveMountEffects(
@@ -3584,21 +3624,29 @@ function recursivelyTraversePassiveMountEffects(
3624 committedLanes: Lanes,
3625 committedTransitions: Array<Transition> | null,
3626 ) {
3587 - const prevDebugFiber = getCurrentDebugFiberInDEV();
3627 if (parentFiber.subtreeFlags & PassiveMask) {
3628 let child = parentFiber.child;
3629 while (child !== null) {
3591 - setCurrentDebugFiberInDEV(child);
3592 - commitPassiveMountOnFiber(
3593 - root,
3594 - child,
3595 - committedLanes,
3596 - committedTransitions,
3597 - );
3630 + if (__DEV__) {
3631 + runWithFiberInDEV(
3632 + child,
3633 + commitPassiveMountOnFiber,
3634 + root,
3635 + child,
3636 + committedLanes,
3637 + committedTransitions,
3638 + );
3639 + } else {
3640 + commitPassiveMountOnFiber(
3641 + root,
3642 + child,
3643 + committedLanes,
3644 + committedTransitions,
3645 + );
3646 + }
3647 child = child.sibling;
3648 }
3649 }
3601 - setCurrentDebugFiberInDEV(prevDebugFiber);
3650 }
3651
3652 function commitPassiveMountOnFiber(
@@ -3835,19 +3883,29 @@ function recursivelyTraverseReconnectPassiveEffects(
3883 (parentFiber.subtreeFlags & PassiveMask) !== NoFlags;
3884
3885 // TODO (Offscreen) Check: flags & (RefStatic | LayoutStatic)
3838 - const prevDebugFiber = getCurrentDebugFiberInDEV();
3886 let child = parentFiber.child;
3887 while (child !== null) {
3841 - reconnectPassiveEffects(
3842 - finishedRoot,
3843 - child,
3844 - committedLanes,
3845 - committedTransitions,
3846 - childShouldIncludeWorkInProgressEffects,
3847 - );
3888 + if (__DEV__) {
3889 + runWithFiberInDEV(
3890 + child,
3891 + reconnectPassiveEffects,
3892 + finishedRoot,
3893 + child,
3894 + committedLanes,
3895 + committedTransitions,
3896 + childShouldIncludeWorkInProgressEffects,
3897 + );
3898 + } else {
3899 + reconnectPassiveEffects(
3900 + finishedRoot,
3901 + child,
3902 + committedLanes,
3903 + committedTransitions,
3904 + childShouldIncludeWorkInProgressEffects,
3905 + );
3906 + }
3907 child = child.sibling;
3908 }
3850 - setCurrentDebugFiberInDEV(prevDebugFiber);
3909 }
3910
3911 export function reconnectPassiveEffects(
@@ -4023,22 +4081,30 @@ function recursivelyTraverseAtomicPassiveEffects(
4081 // "Atomic" effects are ones that need to fire on every commit, even during
4082 // pre-rendering. We call this function when traversing a hidden tree whose
4083 // regular effects are currently disconnected.
4026 - const prevDebugFiber = getCurrentDebugFiberInDEV();
4084 // TODO: Add special flag for atomic effects
4085 if (parentFiber.subtreeFlags & PassiveMask) {
4086 let child = parentFiber.child;
4087 while (child !== null) {
4031 - setCurrentDebugFiberInDEV(child);
4032 - commitAtomicPassiveEffects(
4033 - finishedRoot,
4034 - child,
4035 - committedLanes,
4036 - committedTransitions,
4037 - );
4088 + if (__DEV__) {
4089 + runWithFiberInDEV(
4090 + child,
4091 + commitAtomicPassiveEffects,
4092 + finishedRoot,
4093 + child,
4094 + committedLanes,
4095 + committedTransitions,
4096 + );
4097 + } else {
4098 + commitAtomicPassiveEffects(
4099 + finishedRoot,
4100 + child,
4101 + committedLanes,
4102 + committedTransitions,
4103 + );
4104 + }
4105 child = child.sibling;
4106 }
4107 }
4041 - setCurrentDebugFiberInDEV(prevDebugFiber);
4108 }
4109
4110 function commitAtomicPassiveEffects(
@@ -4094,9 +4160,11 @@ function commitAtomicPassiveEffects(
4160 }
4161
4162 export function commitPassiveUnmountEffects(finishedWork: Fiber): void {
4097 - setCurrentDebugFiberInDEV(finishedWork);
4098 - commitPassiveUnmountOnFiber(finishedWork);
4099 - resetCurrentDebugFiberInDEV();
4163 + if (__DEV__) {
4164 + runWithFiberInDEV(finishedWork, commitPassiveUnmountOnFiber, finishedWork);
4165 + } else {
4166 + commitPassiveUnmountOnFiber(finishedWork);
4167 + }
4168 }
4169
4170 // 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 {
4333 detachAlternateSiblings(parentFiber);
4334 }
4335
4268 - const prevDebugFiber = getCurrentDebugFiberInDEV();
4336 // TODO: Split PassiveMask into separate masks for mount and unmount?
4337 if (parentFiber.subtreeFlags & PassiveMask) {
4338 let child = parentFiber.child;
4339 while (child !== null) {
4273 - setCurrentDebugFiberInDEV(child);
4274 - commitPassiveUnmountOnFiber(child);
4340 + if (__DEV__) {
4341 + runWithFiberInDEV(child, commitPassiveUnmountOnFiber, child);
4342 + } else {
4343 + commitPassiveUnmountOnFiber(child);
4344 + }
4345 child = child.sibling;
4346 }
4347 }
4278 - setCurrentDebugFiberInDEV(prevDebugFiber);
4348 }
4349
4350 function commitPassiveUnmountOnFiber(finishedWork: Fiber): void {
@@ -4346,15 +4415,16 @@ function recursivelyTraverseDisconnectPassiveEffects(parentFiber: Fiber): void {
4415 detachAlternateSiblings(parentFiber);
4416 }
4417
4349 - const prevDebugFiber = getCurrentDebugFiberInDEV();
4418 // TODO: Check PassiveStatic flag
4419 let child = parentFiber.child;
4420 while (child !== null) {
4353 - setCurrentDebugFiberInDEV(child);
4354 - disconnectPassiveEffect(child);
4421 + if (__DEV__) {
4422 + runWithFiberInDEV(child, disconnectPassiveEffect, child);
4423 + } else {
4424 + disconnectPassiveEffect(child);
4425 + }
4426 child = child.sibling;
4427 }
4357 - setCurrentDebugFiberInDEV(prevDebugFiber);
4428 }
4429
4430 export function disconnectPassiveEffect(finishedWork: Fiber): void {
@@ -4399,9 +4469,19 @@ function commitPassiveUnmountEffectsInsideOfDeletedTree_begin(
4469
4470 // Deletion effects fire in parent -> child order
4471 // TODO: Check if fiber has a PassiveStatic flag
4402 - setCurrentDebugFiberInDEV(fiber);
4403 - commitPassiveUnmountInsideDeletedTreeOnFiber(fiber, nearestMountedAncestor);
4404 - resetCurrentDebugFiberInDEV();
4472 + if (__DEV__) {
4473 + runWithFiberInDEV(
4474 + fiber,
4475 + commitPassiveUnmountInsideDeletedTreeOnFiber,
4476 + fiber,
4477 + nearestMountedAncestor,
4478 + );
4479 + } else {
4480 + commitPassiveUnmountInsideDeletedTreeOnFiber(
4481 + fiber,
4482 + nearestMountedAncestor,
4483 + );
4484 + }
4485
4486 const child = fiber.child;
4487 // TODO: Only traverse subtree if it has a PassiveStatic flag.
packages/react-reconciler/src/ReactFiberReconciler.js
+3 -15
@@ -78,8 +78,7 @@ import {
78 import {
79 isRendering as ReactCurrentFiberIsRendering,
80 current as ReactCurrentFiberCurrent,
81 - resetCurrentDebugFiberInDEV,
82 - setCurrentDebugFiberInDEV,
81 + runWithFiberInDEV,
82 } from './ReactCurrentFiber';
83 import {StrictLegacyMode} from './ReactTypeOfMode';
84 import {
@@ -202,10 +201,7 @@ function findHostInstanceWithWarning(
201 const componentName = getComponentNameFromFiber(fiber) || 'Component';
202 if (!didWarnAboutFindNodeInStrictMode[componentName]) {
203 didWarnAboutFindNodeInStrictMode[componentName] = true;
205 -
206 - const previousFiber = ReactCurrentFiberCurrent;
207 - try {
208 - setCurrentDebugFiberInDEV(hostFiber);
204 + runWithFiberInDEV(hostFiber, () => {
205 if (fiber.mode & StrictLegacyMode) {
206 console.error(
207 '%s is deprecated in StrictMode. ' +
@@ -229,15 +225,7 @@ function findHostInstanceWithWarning(
225 componentName,
226 );
227 }
232 - } finally {
233 - // Ideally this should reset to previous but this shouldn't be called in
234 - // render and there's another warning for that anyway.
235 - if (previousFiber) {
236 - setCurrentDebugFiberInDEV(previousFiber);
237 - } else {
238 - resetCurrentDebugFiberInDEV();
239 - }
240 - }
228 + });
229 }
230 }
231 return getPublicInstance(hostFiber.stateNode);
packages/react-reconciler/src/ReactFiberThrow.js
+28 -16
@@ -87,10 +87,7 @@ import {
87 import {ConcurrentRoot} from './ReactRootTags';
88 import {noopSuspenseyCommitThenable} from './ReactFiberThenable';
89 import {REACT_POSTPONE_TYPE} from 'shared/ReactSymbols';
90 -import {
91 - setCurrentDebugFiberInDEV,
92 - getCurrentFiber as getCurrentDebugFiberInDEV,
93 -} from './ReactCurrentFiber';
90 +import {runWithFiberInDEV} from './ReactCurrentFiber';
91
92 function createRootErrorUpdate(
93 root: FiberRoot,
@@ -104,10 +101,11 @@ function createRootErrorUpdate(
101 // being called "element".
102 update.payload = {element: null};
103 update.callback = () => {
107 - const prevFiber = getCurrentDebugFiberInDEV(); // should just be the root
108 - setCurrentDebugFiberInDEV(errorInfo.source);
109 - logUncaughtError(root, errorInfo);
110 - setCurrentDebugFiberInDEV(prevFiber);
104 + if (__DEV__) {
105 + runWithFiberInDEV(errorInfo.source, logUncaughtError, root, errorInfo);
106 + } else {
107 + logUncaughtError(root, errorInfo);
108 + }
109 };
110 return update;
111 }
@@ -134,10 +132,17 @@ function initializeClassErrorUpdate(
132 if (__DEV__) {
133 markFailedErrorBoundaryForHotReloading(fiber);
134 }
137 - const prevFiber = getCurrentDebugFiberInDEV(); // should be the error boundary
138 - setCurrentDebugFiberInDEV(errorInfo.source);
139 - logCaughtError(root, fiber, errorInfo);
140 - setCurrentDebugFiberInDEV(prevFiber);
135 + if (__DEV__) {
136 + runWithFiberInDEV(
137 + errorInfo.source,
138 + logCaughtError,
139 + root,
140 + fiber,
141 + errorInfo,
142 + );
143 + } else {
144 + logCaughtError(root, fiber, errorInfo);
145 + }
146 };
147 }
148
@@ -148,10 +153,17 @@ function initializeClassErrorUpdate(
153 if (__DEV__) {
154 markFailedErrorBoundaryForHotReloading(fiber);
155 }
151 - const prevFiber = getCurrentDebugFiberInDEV(); // should be the error boundary
152 - setCurrentDebugFiberInDEV(errorInfo.source);
153 - logCaughtError(root, fiber, errorInfo);
154 - setCurrentDebugFiberInDEV(prevFiber);
156 + if (__DEV__) {
157 + runWithFiberInDEV(
158 + errorInfo.source,
159 + logCaughtError,
160 + root,
161 + fiber,
162 + errorInfo,
163 + );
164 + } else {
165 + logCaughtError(root, fiber, errorInfo);
166 + }
167 if (typeof getDerivedStateFromError !== 'function') {
168 // To preserve the preexisting retry behavior of error boundaries,
169 // we keep track of which ones already failed during this batch.
packages/react-reconciler/src/ReactFiberWorkLoop.js
+100 -59
@@ -231,10 +231,8 @@ import getComponentNameFromFiber from 'react-reconciler/src/getComponentNameFrom
231 import ReactStrictModeWarnings from './ReactStrictModeWarnings';
232 import {
233 isRendering as ReactCurrentDebugFiberIsRenderingInDEV,
234 - current as ReactCurrentFiberCurrent,
235 - resetCurrentDebugFiberInDEV,
236 - setCurrentDebugFiberInDEV,
234 resetCurrentFiber,
235 + runWithFiberInDEV,
236 } from './ReactCurrentFiber';
237 import {
238 isDevToolsPresent,
@@ -2381,18 +2379,37 @@ function performUnitOfWork(unitOfWork: Fiber): void {
2379 // nothing should rely on this, but relying on it here means that we don't
2380 // need an additional field on the work in progress.
2381 const current = unitOfWork.alternate;
2384 - setCurrentDebugFiberInDEV(unitOfWork);
2382
2383 let next;
2384 if (enableProfilerTimer && (unitOfWork.mode & ProfileMode) !== NoMode) {
2385 startProfilerTimer(unitOfWork);
2389 - next = beginWork(current, unitOfWork, entangledRenderLanes);
2386 + if (__DEV__) {
2387 + next = runWithFiberInDEV(
2388 + unitOfWork,
2389 + beginWork,
2390 + current,
2391 + unitOfWork,
2392 + entangledRenderLanes,
2393 + );
2394 + } else {
2395 + next = beginWork(current, unitOfWork, entangledRenderLanes);
2396 + }
2397 stopProfilerTimerIfRunningAndRecordDelta(unitOfWork, true);
2398 } else {
2392 - next = beginWork(current, unitOfWork, entangledRenderLanes);
2399 + if (__DEV__) {
2400 + next = runWithFiberInDEV(
2401 + unitOfWork,
2402 + beginWork,
2403 + current,
2404 + unitOfWork,
2405 + entangledRenderLanes,
2406 + );
2407 + } else {
2408 + next = beginWork(current, unitOfWork, entangledRenderLanes);
2409 + }
2410 }
2411
2395 - if (__DEV__ || !disableStringRefs) {
2412 + if (!disableStringRefs) {
2413 resetCurrentFiber();
2414 }
2415 unitOfWork.memoizedProps = unitOfWork.pendingProps;
@@ -2407,9 +2424,32 @@ function performUnitOfWork(unitOfWork: Fiber): void {
2424 function replaySuspendedUnitOfWork(unitOfWork: Fiber): void {
2425 // This is a fork of performUnitOfWork specifcally for replaying a fiber that
2426 // just suspended.
2410 - //
2427 + let next;
2428 + if (__DEV__) {
2429 + next = runWithFiberInDEV(unitOfWork, replayBeginWork, unitOfWork);
2430 + } else {
2431 + next = replayBeginWork(unitOfWork);
2432 + }
2433 +
2434 + // The begin phase finished successfully without suspending. Return to the
2435 + // normal work loop.
2436 + if (!disableStringRefs) {
2437 + resetCurrentFiber();
2438 + }
2439 + unitOfWork.memoizedProps = unitOfWork.pendingProps;
2440 + if (next === null) {
2441 + // If this doesn't spawn new work, complete the current work.
2442 + completeUnitOfWork(unitOfWork);
2443 + } else {
2444 + workInProgress = next;
2445 + }
2446 +}
2447 +
2448 +function replayBeginWork(unitOfWork: Fiber): null | Fiber {
2449 + // This is a fork of beginWork specifcally for replaying a fiber that
2450 + // just suspended.
2451 +
2452 const current = unitOfWork.alternate;
2412 - setCurrentDebugFiberInDEV(unitOfWork);
2453
2454 let next;
2455 const isProfilingMode =
@@ -2501,19 +2541,7 @@ function replaySuspendedUnitOfWork(unitOfWork: Fiber): void {
2541 stopProfilerTimerIfRunningAndRecordDelta(unitOfWork, true);
2542 }
2543
2504 - // The begin phase finished successfully without suspending. Return to the
2505 - // normal work loop.
2506 -
2507 - if (__DEV__ || !disableStringRefs) {
2508 - resetCurrentFiber();
2509 - }
2510 - unitOfWork.memoizedProps = unitOfWork.pendingProps;
2511 - if (next === null) {
2512 - // If this doesn't spawn new work, complete the current work.
2513 - completeUnitOfWork(unitOfWork);
2514 - } else {
2515 - workInProgress = next;
2516 - }
2544 + return next;
2545 }
2546
2547 function throwAndUnwindWorkLoop(
@@ -2612,17 +2640,35 @@ function completeUnitOfWork(unitOfWork: Fiber): void {
2640 const current = completedWork.alternate;
2641 const returnFiber = completedWork.return;
2642
2615 - setCurrentDebugFiberInDEV(completedWork);
2643 let next;
2644 if (!enableProfilerTimer || (completedWork.mode & ProfileMode) === NoMode) {
2618 - next = completeWork(current, completedWork, entangledRenderLanes);
2645 + if (__DEV__) {
2646 + next = runWithFiberInDEV(
2647 + completedWork,
2648 + completeWork,
2649 + current,
2650 + completedWork,
2651 + entangledRenderLanes,
2652 + );
2653 + } else {
2654 + next = completeWork(current, completedWork, entangledRenderLanes);
2655 + }
2656 } else {
2657 startProfilerTimer(completedWork);
2621 - next = completeWork(current, completedWork, entangledRenderLanes);
2658 + if (__DEV__) {
2659 + next = runWithFiberInDEV(
2660 + completedWork,
2661 + completeWork,
2662 + current,
2663 + completedWork,
2664 + entangledRenderLanes,
2665 + );
2666 + } else {
2667 + next = completeWork(current, completedWork, entangledRenderLanes);
2668 + }
2669 // Update render duration assuming we didn't error.
2670 stopProfilerTimerIfRunningAndRecordDelta(completedWork, false);
2671 }
2625 - resetCurrentDebugFiberInDEV();
2672
2673 if (next !== null) {
2674 // Completing this fiber spawned new work. Work on that next.
@@ -3045,9 +3091,16 @@ function commitRootImpl(
3091 for (let i = 0; i < recoverableErrors.length; i++) {
3092 const recoverableError = recoverableErrors[i];
3093 const errorInfo = makeErrorInfo(recoverableError.stack);
3048 - setCurrentDebugFiberInDEV(recoverableError.source);
3049 - onRecoverableError(recoverableError.value, errorInfo);
3050 - resetCurrentDebugFiberInDEV();
3094 + if (__DEV__) {
3095 + runWithFiberInDEV(
3096 + recoverableError.source,
3097 + onRecoverableError,
3098 + recoverableError.value,
3099 + errorInfo,
3100 + );
3101 + } else {
3102 + onRecoverableError(recoverableError.value, errorInfo);
3103 + }
3104 }
3105 }
3106
@@ -3698,15 +3751,15 @@ function doubleInvokeEffectsInDEVIfNecessary(
3751 // special rules apply to double invoking effects.
3752 if (fiber.tag !== OffscreenComponent) {
3753 if (fiber.flags & PlacementDEV) {
3701 - setCurrentDebugFiberInDEV(fiber);
3754 if (isInStrictMode) {
3703 - doubleInvokeEffectsOnFiber(
3755 + runWithFiberInDEV(
3756 + fiber,
3757 + doubleInvokeEffectsOnFiber,
3758 root,
3759 fiber,
3760 (fiber.mode & NoStrictPassiveEffectsMode) === NoMode,
3761 );
3762 }
3709 - resetCurrentDebugFiberInDEV();
3763 } else {
3764 recursivelyTraverseAndDoubleInvokeEffectsInDEV(
3765 root,
@@ -3722,21 +3775,21 @@ function doubleInvokeEffectsInDEVIfNecessary(
3775 if (fiber.memoizedState === null) {
3776 // Only consider Offscreen that is visible.
3777 // TODO (Offscreen) Handle manual mode.
3725 - setCurrentDebugFiberInDEV(fiber);
3778 if (isInStrictMode && fiber.flags & Visibility) {
3779 // Double invoke effects on Offscreen's subtree only
3780 // if it is visible and its visibility has changed.
3729 - doubleInvokeEffectsOnFiber(root, fiber);
3781 + runWithFiberInDEV(fiber, doubleInvokeEffectsOnFiber, root, fiber);
3782 } else if (fiber.subtreeFlags & PlacementDEV) {
3783 // Something in the subtree could have been suspended.
3784 // We need to continue traversal and find newly inserted fibers.
3733 - recursivelyTraverseAndDoubleInvokeEffectsInDEV(
3785 + runWithFiberInDEV(
3786 + fiber,
3787 + recursivelyTraverseAndDoubleInvokeEffectsInDEV,
3788 root,
3789 fiber,
3790 isInStrictMode,
3791 );
3792 }
3739 - resetCurrentDebugFiberInDEV();
3793 }
3794 }
3795
@@ -3760,7 +3813,13 @@ function commitDoubleInvokeEffectsInDEV(
3813 doubleInvokeEffects,
3814 );
3815 } else {
3763 - legacyCommitDoubleInvokeEffectsInDEV(root.current, hasPassiveEffects);
3816 + // TODO: Is this runWithFiberInDEV needed since the other effect functions do it too?
3817 + runWithFiberInDEV(
3818 + root.current,
3819 + legacyCommitDoubleInvokeEffectsInDEV,
3820 + root.current,
3821 + hasPassiveEffects,
3822 + );
3823 }
3824 }
3825 }
@@ -3773,7 +3832,6 @@ function legacyCommitDoubleInvokeEffectsInDEV(
3832 // so we don't traverse unnecessarily? similar to subtreeFlags but just at the root level.
3833 // Maybe not a big deal since this is DEV only behavior.
3834
3776 - setCurrentDebugFiberInDEV(fiber);
3835 invokeEffectsInDev(fiber, MountLayoutDev, invokeLayoutEffectUnmountInDEV);
3836 if (hasPassiveEffects) {
3837 invokeEffectsInDev(fiber, MountPassiveDev, invokePassiveEffectUnmountInDEV);
@@ -3783,7 +3841,6 @@ function legacyCommitDoubleInvokeEffectsInDEV(
3841 if (hasPassiveEffects) {
3842 invokeEffectsInDev(fiber, MountPassiveDev, invokePassiveEffectMountInDEV);
3843 }
3786 - resetCurrentDebugFiberInDEV();
3844 }
3845
3846 function invokeEffectsInDev(
@@ -3853,22 +3910,14 @@ export function warnAboutUpdateOnNotYetMountedFiberInDEV(fiber: Fiber) {
3910 didWarnStateUpdateForNotYetMountedComponent = new Set([componentName]);
3911 }
3912
3856 - const previousFiber = ReactCurrentFiberCurrent;
3857 - try {
3858 - setCurrentDebugFiberInDEV(fiber);
3913 + runWithFiberInDEV(fiber, () => {
3914 console.error(
3915 "Can't perform a React state update on a component that hasn't mounted yet. " +
3916 'This indicates that you have a side-effect in your render function that ' +
3917 'asynchronously later calls tries to update the component. Move this work to ' +
3918 'useEffect instead.',
3919 );
3865 - } finally {
3866 - if (previousFiber) {
3867 - setCurrentDebugFiberInDEV(fiber);
3868 - } else {
3869 - resetCurrentDebugFiberInDEV();
3870 - }
3871 - }
3920 + });
3921 }
3922 }
3923
@@ -3990,9 +4039,7 @@ function warnIfUpdatesNotWrappedWithActDEV(fiber: Fiber): void {
4039 }
4040
4041 if (ReactSharedInternals.actQueue === null) {
3993 - const previousFiber = ReactCurrentFiberCurrent;
3994 - try {
3995 - setCurrentDebugFiberInDEV(fiber);
4042 + runWithFiberInDEV(fiber, () => {
4043 console.error(
4044 'An update to %s inside a test was not wrapped in act(...).\n\n' +
4045 'When testing, code that causes React state updates should be ' +
@@ -4006,13 +4053,7 @@ function warnIfUpdatesNotWrappedWithActDEV(fiber: Fiber): void {
4053 ' Learn more at https://react.dev/link/wrap-tests-with-act',
4054 getComponentNameFromFiber(fiber),
4055 );
4009 - } finally {
4010 - if (previousFiber) {
4011 - setCurrentDebugFiberInDEV(fiber);
4012 - } else {
4013 - resetCurrentDebugFiberInDEV();
4014 - }
4015 - }
4056 + });
4057 }
4058 }
4059 }
packages/react-reconciler/src/ReactStrictModeWarnings.js
+3 -9
@@ -9,10 +9,7 @@
9
10 import type {Fiber} from './ReactInternalTypes';
11
12 -import {
13 - resetCurrentDebugFiberInDEV,
14 - setCurrentDebugFiberInDEV,
15 -} from './ReactCurrentFiber';
12 +import {runWithFiberInDEV} from './ReactCurrentFiber';
13 import getComponentNameFromFiber from 'react-reconciler/src/getComponentNameFromFiber';
14 import {StrictLegacyMode} from './ReactTypeOfMode';
15
@@ -339,8 +336,7 @@ if (__DEV__) {
336
337 const sortedNames = setToSortedString(uniqueNames);
338
342 - try {
343 - setCurrentDebugFiberInDEV(firstFiber);
339 + runWithFiberInDEV(firstFiber, () => {
340 console.error(
341 'Legacy context API has been detected within a strict-mode tree.' +
342 '\n\nThe old API will be supported in all 16.x releases, but applications ' +
@@ -349,9 +345,7 @@ if (__DEV__) {
345 '\n\nLearn more about this warning here: https://react.dev/link/legacy-context',
346 sortedNames,
347 );
352 - } finally {
353 - resetCurrentDebugFiberInDEV();
354 - }
348 + });
349 },
350 );
351 };