Fix warning about setState in useEffect (#24295)
* Fix warning about setState in useEffect * Fix test * Fix multiple roots
dan committed
Apr 7, 2022 at 18:06 UTC
d68b09defca37c30d3a7a34d4de884e374c74858
2 files changed
+68
-8
packages/react-reconciler/src/ReactFiberWorkLoop.new.js
+34
-4
@@ -396,9 +396,12 @@ let pendingPassiveEffectsRemainingLanes: Lanes = NoLanes;
396
const NESTED_UPDATE_LIMIT = 50;
397
let nestedUpdateCount: number = 0;
398
let rootWithNestedUpdates: FiberRoot | null = null;
399
+let isFlushingPassiveEffects = false;
400
+let didScheduleUpdateDuringPassiveEffects = false;
401
402
const NESTED_PASSIVE_UPDATE_LIMIT = 50;
403
let nestedPassiveUpdateCount: number = 0;
404
+let rootWithPassiveNestedUpdates: FiberRoot | null = null;
405
406
// If two updates are scheduled within the same event, we should treat their
407
// event times as simultaneous, even if the actual clock time has advanced
@@ -522,6 +525,12 @@ export function scheduleUpdateOnFiber(
525
return null;
526
}
527
528
+ if (__DEV__) {
529
+ if (isFlushingPassiveEffects) {
530
+ didScheduleUpdateDuringPassiveEffects = true;
531
+ }
532
+ }
533
+
534
// Mark that the root has a pending update.
535
markRootUpdated(root, lane, eventTime);
536
@@ -2204,6 +2213,10 @@ function commitRootImpl(
2213
// There were no passive effects, so we can immediately release the cache
2214
// pool for this render.
2215
releaseRootPooledCache(root, remainingLanes);
2216
+ if (__DEV__) {
2217
+ nestedPassiveUpdateCount = 0;
2218
+ rootWithPassiveNestedUpdates = null;
2219
+ }
2220
}
2221
2222
// Read this again, since an effect might have updated it
@@ -2420,6 +2433,9 @@ function flushPassiveEffectsImpl() {
2433
}
2434
2435
if (__DEV__) {
2436
+ isFlushingPassiveEffects = true;
2437
+ didScheduleUpdateDuringPassiveEffects = false;
2438
+
2439
if (enableDebugTracing) {
2440
logPassiveEffectsStarted(lanes);
2441
}
@@ -2463,10 +2479,22 @@ function flushPassiveEffectsImpl() {
2479
2480
flushSyncCallbacks();
2481
2466
- // If additional passive effects were scheduled, increment a counter. If this
2467
- // exceeds the limit, we'll fire a warning.
2468
- nestedPassiveUpdateCount =
2469
- rootWithPendingPassiveEffects === null ? 0 : nestedPassiveUpdateCount + 1;
2482
+ if (__DEV__) {
2483
+ // If additional passive effects were scheduled, increment a counter. If this
2484
+ // exceeds the limit, we'll fire a warning.
2485
+ if (didScheduleUpdateDuringPassiveEffects) {
2486
+ if (root === rootWithPassiveNestedUpdates) {
2487
+ nestedPassiveUpdateCount++;
2488
+ } else {
2489
+ nestedPassiveUpdateCount = 0;
2490
+ rootWithPassiveNestedUpdates = root;
2491
+ }
2492
+ } else {
2493
+ nestedPassiveUpdateCount = 0;
2494
+ }
2495
+ isFlushingPassiveEffects = false;
2496
+ didScheduleUpdateDuringPassiveEffects = false;
2497
+ }
2498
2499
// TODO: Move to commitPassiveMountEffects
2500
onPostCommitRootDevTools(root);
@@ -2739,6 +2767,8 @@ function checkForNestedUpdates() {
2767
if (__DEV__) {
2768
if (nestedPassiveUpdateCount > NESTED_PASSIVE_UPDATE_LIMIT) {
2769
nestedPassiveUpdateCount = 0;
2770
+ rootWithPassiveNestedUpdates = null;
2771
+
2772
console.error(
2773
'Maximum update depth exceeded. This can happen when a component ' +
2774
"calls setState inside useEffect, but useEffect either doesn't " +
packages/react-reconciler/src/ReactFiberWorkLoop.old.js
+34
-4
@@ -396,9 +396,12 @@ let pendingPassiveEffectsRemainingLanes: Lanes = NoLanes;
396
const NESTED_UPDATE_LIMIT = 50;
397
let nestedUpdateCount: number = 0;
398
let rootWithNestedUpdates: FiberRoot | null = null;
399
+let isFlushingPassiveEffects = false;
400
+let didScheduleUpdateDuringPassiveEffects = false;
401
402
const NESTED_PASSIVE_UPDATE_LIMIT = 50;
403
let nestedPassiveUpdateCount: number = 0;
404
+let rootWithPassiveNestedUpdates: FiberRoot | null = null;
405
406
// If two updates are scheduled within the same event, we should treat their
407
// event times as simultaneous, even if the actual clock time has advanced
@@ -522,6 +525,12 @@ export function scheduleUpdateOnFiber(
525
return null;
526
}
527
528
+ if (__DEV__) {
529
+ if (isFlushingPassiveEffects) {
530
+ didScheduleUpdateDuringPassiveEffects = true;
531
+ }
532
+ }
533
+
534
// Mark that the root has a pending update.
535
markRootUpdated(root, lane, eventTime);
536
@@ -2204,6 +2213,10 @@ function commitRootImpl(
2213
// There were no passive effects, so we can immediately release the cache
2214
// pool for this render.
2215
releaseRootPooledCache(root, remainingLanes);
2216
+ if (__DEV__) {
2217
+ nestedPassiveUpdateCount = 0;
2218
+ rootWithPassiveNestedUpdates = null;
2219
+ }
2220
}
2221
2222
// Read this again, since an effect might have updated it
@@ -2420,6 +2433,9 @@ function flushPassiveEffectsImpl() {
2433
}
2434
2435
if (__DEV__) {
2436
+ isFlushingPassiveEffects = true;
2437
+ didScheduleUpdateDuringPassiveEffects = false;
2438
+
2439
if (enableDebugTracing) {
2440
logPassiveEffectsStarted(lanes);
2441
}
@@ -2463,10 +2479,22 @@ function flushPassiveEffectsImpl() {
2479
2480
flushSyncCallbacks();
2481
2466
- // If additional passive effects were scheduled, increment a counter. If this
2467
- // exceeds the limit, we'll fire a warning.
2468
- nestedPassiveUpdateCount =
2469
- rootWithPendingPassiveEffects === null ? 0 : nestedPassiveUpdateCount + 1;
2482
+ if (__DEV__) {
2483
+ // If additional passive effects were scheduled, increment a counter. If this
2484
+ // exceeds the limit, we'll fire a warning.
2485
+ if (didScheduleUpdateDuringPassiveEffects) {
2486
+ if (root === rootWithPassiveNestedUpdates) {
2487
+ nestedPassiveUpdateCount++;
2488
+ } else {
2489
+ nestedPassiveUpdateCount = 0;
2490
+ rootWithPassiveNestedUpdates = root;
2491
+ }
2492
+ } else {
2493
+ nestedPassiveUpdateCount = 0;
2494
+ }
2495
+ isFlushingPassiveEffects = false;
2496
+ didScheduleUpdateDuringPassiveEffects = false;
2497
+ }
2498
2499
// TODO: Move to commitPassiveMountEffects
2500
onPostCommitRootDevTools(root);
@@ -2739,6 +2767,8 @@ function checkForNestedUpdates() {
2767
if (__DEV__) {
2768
if (nestedPassiveUpdateCount > NESTED_PASSIVE_UPDATE_LIMIT) {
2769
nestedPassiveUpdateCount = 0;
2770
+ rootWithPassiveNestedUpdates = null;
2771
+
2772
console.error(
2773
'Maximum update depth exceeded. This can happen when a component ' +
2774
"calls setState inside useEffect, but useEffect either doesn't " +