[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
};