@@ -20,7 +20,7 @@ import type {ReactPriorityLevel} from './SchedulerWithReactIntegration';
20
20
21
21
import ReactSharedInternals from 'shared/ReactSharedInternals' ;
22
22
23
- import { NoWork , Sync } from './ReactFiberExpirationTime' ;
23
+ import { NoWork } from './ReactFiberExpirationTime' ;
24
24
import { readContext } from './ReactFiberNewContext' ;
25
25
import { createResponderListener } from './ReactFiberEvents' ;
26
26
import {
@@ -108,13 +108,13 @@ type Update<S, A> = {
108
108
action : A ,
109
109
eagerReducer : ( ( S , A ) => S ) | null ,
110
110
eagerState : S | null ,
111
- next : Update < S , A> ,
111
+ next : Update < S , A> | null ,
112
112
113
113
priority ?: ReactPriorityLevel ,
114
114
} ;
115
115
116
116
type UpdateQueue < S , A > = {
117
- pending : Update < S , A> | null ,
117
+ last : Update < S , A> | null ,
118
118
dispatch : ( A => mixed ) | null ,
119
119
lastRenderedReducer : ( ( S , A ) => S ) | null ,
120
120
lastRenderedState : S | null ,
@@ -144,7 +144,7 @@ export type Hook = {
144
144
memoizedState : any ,
145
145
146
146
baseState : any ,
147
- baseQueue : Update < any , any > | null ,
147
+ baseUpdate : Update < any , any > | null ,
148
148
queue : UpdateQueue < any , any > | null ,
149
149
150
150
next : Hook | null ,
@@ -544,8 +544,8 @@ function mountWorkInProgressHook(): Hook {
544
544
memoizedState: null,
545
545
546
546
baseState: null,
547
- baseQueue : null ,
548
547
queue: null,
548
+ baseUpdate: null,
549
549
550
550
next: null,
551
551
};
@@ -604,8 +604,8 @@ function updateWorkInProgressHook(): Hook {
604
604
memoizedState: currentHook.memoizedState,
605
605
606
606
baseState: currentHook.baseState,
607
- baseQueue : currentHook . baseQueue ,
608
607
queue: currentHook.queue,
608
+ baseUpdate: currentHook.baseUpdate,
609
609
610
610
next: null,
611
611
};
@@ -645,7 +645,7 @@ function mountReducer<S, I, A>(
645
645
}
646
646
hook.memoizedState = hook.baseState = initialState;
647
647
const queue = (hook.queue = {
648
- pending : null ,
648
+ last : null,
649
649
dispatch: null,
650
650
lastRenderedReducer: reducer,
651
651
lastRenderedState: (initialState: any),
@@ -703,7 +703,7 @@ function updateReducer<S, I, A>(
703
703
// the base state unless the queue is empty.
704
704
// TODO: Not sure if this is the desired semantics, but it's what we
705
705
// do for gDSFP. I can't remember why.
706
- if ( hook . baseQueue === null ) {
706
+ if (hook.baseUpdate === queue.last ) {
707
707
hook.baseState = newState;
708
708
}
709
709
@@ -715,55 +715,42 @@ function updateReducer<S, I, A>(
715
715
return [hook.memoizedState, dispatch];
716
716
}
717
717
718
- const current: Hook = (currentHook: any);
719
-
720
- // The last rebase update that is NOT part of the base state.
721
- let baseQueue = current.baseQueue;
722
-
723
- // The last pending update that hasn't been processed yet.
724
- let pendingQueue = queue.pending;
725
- if (pendingQueue !== null) {
726
- // We have new updates that haven't been processed yet.
727
- // We'll add them to the base queue.
728
- if ( baseQueue !== null ) {
729
- // Merge the pending queue and the base queue.
730
- let baseFirst = baseQueue . next ;
731
- let pendingFirst = pendingQueue . next ;
732
- baseQueue . next = pendingFirst ;
733
- pendingQueue . next = baseFirst ;
718
+ // The last update in the entire queue
719
+ const last = queue.last;
720
+ // The last update that is part of the base state.
721
+ const baseUpdate = hook.baseUpdate;
722
+ const baseState = hook.baseState;
723
+
724
+ // Find the first unprocessed update.
725
+ let first;
726
+ if (baseUpdate !== null) {
727
+ if (last !== null) {
728
+ // For the first update, the queue is a circular linked list where
729
+ // ` queue . last . next = queue . first `. Once the first update commits, and
730
+ // the ` baseUpdate ` is no longer empty , we can unravel the list .
731
+ last . next = null ;
734
732
}
735
- current.baseQueue = baseQueue = pendingQueue;
736
- queue.pending = null;
733
+ first = baseUpdate . next ;
734
+ } else {
735
+ first = last !== null ? last . next : null ;
737
736
}
738
-
739
- if ( baseQueue !== null ) {
740
- // We have a queue to process.
741
- let first = baseQueue . next ;
742
- let newState = current . baseState ;
743
-
737
+ if ( first !== null ) {
738
+ let newState = baseState ;
744
739
let newBaseState = null ;
745
- let newBaseQueueFirst = null ;
746
- let newBaseQueueLast = null ;
740
+ let newBaseUpdate = null ;
741
+ let prevUpdate = baseUpdate ;
747
742
let update = first ;
743
+ let didSkip = false ;
748
744
do {
749
745
const updateExpirationTime = update . expirationTime ;
750
746
if ( updateExpirationTime < renderExpirationTime ) {
751
747
// Priority is insufficient. Skip this update. If this is the first
752
748
// skipped update, the previous update/state is the new base
753
749
// update/state.
754
- const clone : Update < S , A> = {
755
- expirationTime : update . expirationTime ,
756
- suspenseConfig : update . suspenseConfig ,
757
- action : update . action ,
758
- eagerReducer : update . eagerReducer ,
759
- eagerState : update . eagerState ,
760
- next : ( null : any ) ,
761
- } ;
762
- if ( newBaseQueueLast === null ) {
763
- newBaseQueueFirst = newBaseQueueLast = clone ;
750
+ if ( ! didSkip ) {
751
+ didSkip = true ;
752
+ newBaseUpdate = prevUpdate ;
764
753
newBaseState = newState ;
765
- } else {
766
- newBaseQueueLast = newBaseQueueLast . next = clone ;
767
754
}
768
755
// Update the remaining priority in the queue.
769
756
if ( updateExpirationTime > currentlyRenderingFiber . expirationTime ) {
@@ -773,18 +760,6 @@ function updateReducer<S, I, A>(
773
760
} else {
774
761
// This update does have sufficient priority.
775
762
776
- if ( newBaseQueueLast !== null ) {
777
- const clone : Update < S , A> = {
778
- expirationTime : Sync , // This update is going to be committed so we never want uncommit it.
779
- suspenseConfig : update . suspenseConfig ,
780
- action : update . action ,
781
- eagerReducer : update . eagerReducer ,
782
- eagerState : update . eagerState ,
783
- next : ( null : any ) ,
784
- } ;
785
- newBaseQueueLast = newBaseQueueLast . next = clone ;
786
- }
787
-
788
763
// Mark the event time of this update as relevant to this render pass.
789
764
// TODO: This should ideally use the true event time of this update rather than
790
765
// its priority which is a derived and not reverseable value.
@@ -806,13 +781,13 @@ function updateReducer<S, I, A>(
806
781
newState = reducer ( newState , action) ;
807
782
}
808
783
}
784
+ prevUpdate = update ;
809
785
update = update . next ;
810
786
} while ( update !== null && update !== first ) ;
811
787
812
- if ( newBaseQueueLast === null ) {
788
+ if ( ! didSkip ) {
789
+ newBaseUpdate = prevUpdate ;
813
790
newBaseState = newState ;
814
- } else {
815
- newBaseQueueLast. next = ( newBaseQueueFirst : any ) ;
816
791
}
817
792
818
793
// Mark that the fiber performed work, but only if the new state is
@@ -822,8 +797,8 @@ function updateReducer<S, I, A>(
822
797
}
823
798
824
799
hook . memoizedState = newState ;
800
+ hook . baseUpdate = newBaseUpdate ;
825
801
hook . baseState = newBaseState ;
826
- hook . baseQueue = newBaseQueueLast ;
827
802
828
803
queue . lastRenderedState = newState ;
829
804
}
@@ -841,7 +816,7 @@ function mountState<S>(
841
816
}
842
817
hook . memoizedState = hook . baseState = initialState ;
843
818
const queue = ( hook . queue = {
844
- pending : null ,
819
+ last : null ,
845
820
dispatch : null ,
846
821
lastRenderedReducer : basicStateReducer ,
847
822
lastRenderedState : ( initialState : any ) ,
@@ -1258,7 +1233,7 @@ function dispatchAction<S, A>(
1258
1233
action,
1259
1234
eagerReducer : null ,
1260
1235
eagerState : null ,
1261
- next : ( null : any ) ,
1236
+ next : null ,
1262
1237
} ;
1263
1238
if ( __DEV__ ) {
1264
1239
update . priority = getCurrentPriorityLevel ( ) ;
@@ -1292,23 +1267,27 @@ function dispatchAction<S, A>(
1292
1267
action,
1293
1268
eagerReducer : null ,
1294
1269
eagerState : null ,
1295
- next : ( null : any ) ,
1270
+ next : null ,
1296
1271
} ;
1297
1272
1298
1273
if ( __DEV__ ) {
1299
1274
update . priority = getCurrentPriorityLevel ( ) ;
1300
1275
}
1301
1276
1302
1277
// Append the update to the end of the list.
1303
- const pending = queue.pending ;
1304
- if (pending === null) {
1278
+ const last = queue.last ;
1279
+ if (last === null) {
1305
1280
// This is the first update. Create a circular list.
1306
1281
update . next = update ;
1307
1282
} else {
1308
- update . next = pending . next ;
1309
- pending . next = update ;
1283
+ const first = last . next ;
1284
+ if ( first !== null ) {
1285
+ // Still circular.
1286
+ update. next = first ;
1287
+ }
1288
+ last.next = update;
1310
1289
}
1311
- queue.pending = update;
1290
+ queue . last = update ;
1312
1291
1313
1292
if (
1314
1293
fiber . expirationTime === NoWork &&
0 commit comments