@@ -198,7 +198,8 @@ let renderPhaseUpdates: Map<
198
198
UpdateQueue < any , any > ,
199
199
Update < any , any > ,
200
200
> | null = null ;
201
-
201
+ // Counter to prevent infinite loops.
202
+ let numberOfReRenders : number = 0 ;
202
203
const RE_RENDER_LIMIT = 25 ;
203
204
204
205
// In DEV, this is the name of the currently executing primitive hook
@@ -397,6 +398,7 @@ export function renderWithHooks(
397
398
398
399
// didScheduleRenderPhaseUpdate = false;
399
400
// renderPhaseUpdates = null;
401
+ // numberOfReRenders = 0;
400
402
401
403
// TODO Warn if no hooks are used at all during mount, then some are used during update.
402
404
// Currently we will identify the update render as a mount because memoizedState === null.
@@ -428,17 +430,8 @@ export function renderWithHooks(
428
430
let children = Component(props, refOrContext);
429
431
430
432
if (didScheduleRenderPhaseUpdate) {
431
- // Counter to prevent infinite loops.
432
- let numberOfReRenders: number = 0;
433
433
do {
434
434
didScheduleRenderPhaseUpdate = false;
435
-
436
- invariant(
437
- numberOfReRenders < RE_RENDER_LIMIT,
438
- 'Too many re-renders. React limits the number of renders to prevent ' +
439
- 'an infinite loop.',
440
- );
441
-
442
435
numberOfReRenders += 1;
443
436
if (__DEV__) {
444
437
// Even when hot reloading, allow dependencies to stabilize
@@ -465,6 +458,7 @@ export function renderWithHooks(
465
458
} while (didScheduleRenderPhaseUpdate);
466
459
467
460
renderPhaseUpdates = null;
461
+ numberOfReRenders = 0;
468
462
}
469
463
470
464
// We can assume the previous dispatcher is always this one, since we set it
@@ -495,6 +489,7 @@ export function renderWithHooks(
495
489
// These were reset above
496
490
// didScheduleRenderPhaseUpdate = false;
497
491
// renderPhaseUpdates = null;
492
+ // numberOfReRenders = 0;
498
493
499
494
invariant(
500
495
!didRenderTooFewHooks,
@@ -541,6 +536,7 @@ export function resetHooks(): void {
541
536
542
537
didScheduleRenderPhaseUpdate = false;
543
538
renderPhaseUpdates = null;
539
+ numberOfReRenders = 0;
544
540
}
545
541
546
542
function mountWorkInProgressHook(): Hook {
@@ -676,43 +672,45 @@ function updateReducer<S, I, A>(
676
672
677
673
queue.lastRenderedReducer = reducer;
678
674
679
- if (renderPhaseUpdates !== null ) {
675
+ if (numberOfReRenders > 0 ) {
680
676
// This is a re-render. Apply the new render phase updates to the previous
681
677
// work-in-progress hook.
682
678
const dispatch: Dispatch<A> = (queue.dispatch: any);
683
- // Render phase updates are stored in a map of queue -> linked list
684
- const firstRenderPhaseUpdate = renderPhaseUpdates.get(queue);
685
- if (firstRenderPhaseUpdate !== undefined) {
686
- renderPhaseUpdates.delete(queue);
687
- let newState = hook.memoizedState;
688
- let update = firstRenderPhaseUpdate;
689
- do {
690
- // Process this render phase update. We don't have to check the
691
- // priority because it will always be the same as the current
692
- // render's.
693
- const action = update.action;
694
- newState = reducer(newState, action);
695
- update = update.next;
696
- } while (update !== null);
697
-
698
- // Mark that the fiber performed work, but only if the new state is
699
- // different from the current state.
700
- if (!is(newState, hook.memoizedState)) {
701
- markWorkInProgressReceivedUpdate();
702
- }
679
+ if (renderPhaseUpdates !== null) {
680
+ // Render phase updates are stored in a map of queue -> linked list
681
+ const firstRenderPhaseUpdate = renderPhaseUpdates.get(queue);
682
+ if (firstRenderPhaseUpdate !== undefined) {
683
+ renderPhaseUpdates.delete(queue);
684
+ let newState = hook.memoizedState;
685
+ let update = firstRenderPhaseUpdate;
686
+ do {
687
+ // Process this render phase update. We don't have to check the
688
+ // priority because it will always be the same as the current
689
+ // render's.
690
+ const action = update.action;
691
+ newState = reducer(newState, action);
692
+ update = update.next;
693
+ } while (update !== null);
703
694
704
- hook.memoizedState = newState;
705
- // Don't persist the state accumulated from the render phase updates to
706
- // the base state unless the queue is empty.
707
- // TODO: Not sure if this is the desired semantics, but it's what we
708
- // do for gDSFP. I can't remember why.
709
- if (hook.baseUpdate === queue.last) {
710
- hook.baseState = newState;
711
- }
695
+ // Mark that the fiber performed work, but only if the new state is
696
+ // different from the current state.
697
+ if (!is(newState, hook.memoizedState)) {
698
+ markWorkInProgressReceivedUpdate();
699
+ }
700
+
701
+ hook.memoizedState = newState;
702
+ // Don't persist the state accumulated from the render phase updates to
703
+ // the base state unless the queue is empty.
704
+ // TODO: Not sure if this is the desired semantics, but it's what we
705
+ // do for gDSFP. I can't remember why.
706
+ if (hook.baseUpdate === queue.last) {
707
+ hook.baseState = newState;
708
+ }
712
709
713
- queue.lastRenderedState = newState;
710
+ queue.lastRenderedState = newState;
714
711
715
- return [newState, dispatch];
712
+ return [newState, dispatch];
713
+ }
716
714
}
717
715
return [hook.memoizedState, dispatch];
718
716
}
@@ -1205,6 +1203,12 @@ function dispatchAction<S, A>(
1205
1203
queue: UpdateQueue< S , A > ,
1206
1204
action: A,
1207
1205
) {
1206
+ invariant (
1207
+ numberOfReRenders < RE_RENDER_LIMIT ,
1208
+ 'Too many re-renders. React limits the number of renders to prevent ' +
1209
+ 'an infinite loop.' ,
1210
+ ) ;
1211
+
1208
1212
if ( __DEV__ ) {
1209
1213
warning (
1210
1214
typeof arguments [ 3 ] !== 'function' ,
0 commit comments