@@ -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 ,
@@ -544,8 +544,8 @@ function mountWorkInProgressHook(): Hook {
544
544
memoizedState : null ,
545
545
546
546
baseState : null ,
547
+ baseQueue : null ,
547
548
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 ,
607
608
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
- last : null,
648
+ pending : 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.baseUpdate === queue.last ) {
706
+ if ( hook . baseQueue === null ) {
707
707
hook . baseState = newState ;
708
708
}
709
709
@@ -715,42 +715,55 @@ function updateReducer<S, I, A>(
715
715
return [ hook . memoizedState , dispatch ] ;
716
716
}
717
717
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 ;
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 ;
732
734
}
733
- first = baseUpdate . next ;
734
- } else {
735
- first = last !== null ? last . next : null ;
735
+ current.baseQueue = baseQueue = pendingQueue;
736
+ queue.pending = null;
736
737
}
737
- if ( first !== null ) {
738
- let newState = baseState ;
738
+
739
+ if ( baseQueue !== null ) {
740
+ // We have a queue to process.
741
+ let first = baseQueue . next ;
742
+ let newState = current . baseState ;
743
+
739
744
let newBaseState = null ;
740
- let newBaseUpdate = null ;
741
- let prevUpdate = baseUpdate ;
745
+ let newBaseQueueFirst = null ;
746
+ let newBaseQueueLast = null ;
742
747
let update = first ;
743
- let didSkip = false ;
744
748
do {
745
749
const updateExpirationTime = update . expirationTime ;
746
750
if ( updateExpirationTime < renderExpirationTime ) {
747
751
// Priority is insufficient. Skip this update. If this is the first
748
752
// skipped update, the previous update/state is the new base
749
753
// update/state.
750
- if ( ! didSkip ) {
751
- didSkip = true ;
752
- newBaseUpdate = prevUpdate ;
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 ;
753
764
newBaseState = newState ;
765
+ } else {
766
+ newBaseQueueLast = newBaseQueueLast . next = clone ;
754
767
}
755
768
// Update the remaining priority in the queue.
756
769
if ( updateExpirationTime > currentlyRenderingFiber . expirationTime ) {
@@ -760,6 +773,18 @@ function updateReducer<S, I, A>(
760
773
} else {
761
774
// This update does have sufficient priority.
762
775
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
+
763
788
// Mark the event time of this update as relevant to this render pass.
764
789
// TODO: This should ideally use the true event time of this update rather than
765
790
// its priority which is a derived and not reverseable value.
@@ -781,13 +806,13 @@ function updateReducer<S, I, A>(
781
806
newState = reducer ( newState , action ) ;
782
807
}
783
808
}
784
- prevUpdate = update ;
785
809
update = update . next ;
786
810
} while ( update !== null && update !== first ) ;
787
811
788
- if ( ! didSkip ) {
789
- newBaseUpdate = prevUpdate ;
812
+ if ( newBaseQueueLast === null ) {
790
813
newBaseState = newState ;
814
+ } else {
815
+ newBaseQueueLast. next = ( newBaseQueueFirst : any ) ;
791
816
}
792
817
793
818
// Mark that the fiber performed work, but only if the new state is
@@ -797,8 +822,8 @@ function updateReducer<S, I, A>(
797
822
}
798
823
799
824
hook . memoizedState = newState ;
800
- hook . baseUpdate = newBaseUpdate ;
801
825
hook . baseState = newBaseState ;
826
+ hook . baseQueue = newBaseQueueLast ;
802
827
803
828
queue . lastRenderedState = newState ;
804
829
}
@@ -816,7 +841,7 @@ function mountState<S>(
816
841
}
817
842
hook . memoizedState = hook . baseState = initialState ;
818
843
const queue = ( hook . queue = {
819
- last : null ,
844
+ pending : null ,
820
845
dispatch : null ,
821
846
lastRenderedReducer : basicStateReducer ,
822
847
lastRenderedState : ( initialState : any ) ,
@@ -1233,7 +1258,7 @@ function dispatchAction<S, A>(
1233
1258
action,
1234
1259
eagerReducer : null ,
1235
1260
eagerState : null ,
1236
- next : null ,
1261
+ next : ( null : any ) ,
1237
1262
} ;
1238
1263
if ( __DEV__ ) {
1239
1264
update . priority = getCurrentPriorityLevel ( ) ;
@@ -1267,27 +1292,23 @@ function dispatchAction<S, A>(
1267
1292
action,
1268
1293
eagerReducer : null ,
1269
1294
eagerState : null ,
1270
- next : null ,
1295
+ next : ( null : any ) ,
1271
1296
} ;
1272
1297
1273
1298
if ( __DEV__ ) {
1274
1299
update . priority = getCurrentPriorityLevel ( ) ;
1275
1300
}
1276
1301
1277
1302
// Append the update to the end of the list.
1278
- const last = queue.last ;
1279
- if (last === null) {
1303
+ const pending = queue.pending ;
1304
+ if (pending === null) {
1280
1305
// This is the first update. Create a circular list.
1281
1306
update . next = update ;
1282
1307
} else {
1283
- const first = last . next ;
1284
- if ( first !== null ) {
1285
- // Still circular.
1286
- update. next = first ;
1287
- }
1288
- last.next = update;
1308
+ update . next = pending . next ;
1309
+ pending . next = update ;
1289
1310
}
1290
- queue . last = update ;
1311
+ queue.pending = update;
1291
1312
1292
1313
if (
1293
1314
fiber.expirationTime === NoWork &&
0 commit comments