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