@@ -20,7 +20,7 @@ import type {ReactPriorityLevel} from './SchedulerWithReactIntegration';
2020
2121import ReactSharedInternals from 'shared/ReactSharedInternals' ;
2222
23- import { NoWork } from './ReactFiberExpirationTime' ;
23+ import { NoWork , Sync } from './ReactFiberExpirationTime' ;
2424import { readContext } from './ReactFiberNewContext' ;
2525import { createResponderListener } from './ReactFiberEvents' ;
2626import {
@@ -108,13 +108,13 @@ type Update<S, A> = {
108108 action : A ,
109109 eagerReducer : ( ( S , A ) => S ) | null ,
110110 eagerState : S | null ,
111- next : Update < S , A> | null ,
111+ next : Update < S , A> ,
112112
113113 priority ?: ReactPriorityLevel ,
114114} ;
115115
116116type UpdateQueue < S , A > = {
117- last : Update < S , A> | null ,
117+ pending : Update < S , A> | null ,
118118 dispatch : ( A => mixed ) | null ,
119119 lastRenderedReducer : ( ( S , A ) => S ) | null ,
120120 lastRenderedState : S | null ,
@@ -144,7 +144,7 @@ export type Hook = {
144144 memoizedState : any ,
145145
146146 baseState : any ,
147- baseUpdate : Update < any , any > | null ,
147+ baseQueue : Update < any , any > | null ,
148148 queue : UpdateQueue < any , any > | null ,
149149
150150 next : Hook | null ,
@@ -544,8 +544,8 @@ function mountWorkInProgressHook(): Hook {
544544 memoizedState : null ,
545545
546546 baseState : null ,
547+ baseQueue : null ,
547548 queue : null ,
548- baseUpdate: null,
549549
550550 next : null ,
551551 } ;
@@ -604,8 +604,8 @@ function updateWorkInProgressHook(): Hook {
604604 memoizedState : currentHook . memoizedState ,
605605
606606 baseState : currentHook . baseState ,
607+ baseQueue : currentHook . baseQueue ,
607608 queue : currentHook . queue ,
608- baseUpdate: currentHook.baseUpdate,
609609
610610 next : null ,
611611 } ;
@@ -645,7 +645,7 @@ function mountReducer<S, I, A>(
645645 }
646646 hook.memoizedState = hook.baseState = initialState;
647647 const queue = (hook.queue = {
648- last : null,
648+ pending : null ,
649649 dispatch : null ,
650650 lastRenderedReducer : reducer ,
651651 lastRenderedState : ( initialState : any ) ,
@@ -703,7 +703,7 @@ function updateReducer<S, I, A>(
703703 // the base state unless the queue is empty.
704704 // TODO: Not sure if this is the desired semantics, but it's what we
705705 // do for gDSFP. I can't remember why.
706- if (hook.baseUpdate === queue.last ) {
706+ if ( hook . baseQueue === null ) {
707707 hook . baseState = newState ;
708708 }
709709
@@ -715,42 +715,55 @@ function updateReducer<S, I, A>(
715715 return [ hook . memoizedState , dispatch ] ;
716716 }
717717
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 ;
732734 }
733- first = baseUpdate . next ;
734- } else {
735- first = last !== null ? last . next : null ;
735+ current.baseQueue = baseQueue = pendingQueue;
736+ queue.pending = null;
736737 }
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+
739744 let newBaseState = null ;
740- let newBaseUpdate = null ;
741- let prevUpdate = baseUpdate ;
745+ let newBaseQueueFirst = null ;
746+ let newBaseQueueLast = null ;
742747 let update = first ;
743- let didSkip = false ;
744748 do {
745749 const updateExpirationTime = update . expirationTime ;
746750 if ( updateExpirationTime < renderExpirationTime ) {
747751 // Priority is insufficient. Skip this update. If this is the first
748752 // skipped update, the previous update/state is the new base
749753 // 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 ;
753764 newBaseState = newState ;
765+ } else {
766+ newBaseQueueLast = newBaseQueueLast . next = clone ;
754767 }
755768 // Update the remaining priority in the queue.
756769 if ( updateExpirationTime > currentlyRenderingFiber . expirationTime ) {
@@ -760,6 +773,18 @@ function updateReducer<S, I, A>(
760773 } else {
761774 // This update does have sufficient priority.
762775
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+
763788 // Mark the event time of this update as relevant to this render pass.
764789 // TODO: This should ideally use the true event time of this update rather than
765790 // its priority which is a derived and not reverseable value.
@@ -781,13 +806,13 @@ function updateReducer<S, I, A>(
781806 newState = reducer ( newState , action ) ;
782807 }
783808 }
784- prevUpdate = update ;
785809 update = update . next ;
786810 } while ( update !== null && update !== first ) ;
787811
788- if ( ! didSkip ) {
789- newBaseUpdate = prevUpdate ;
812+ if ( newBaseQueueLast === null ) {
790813 newBaseState = newState ;
814+ } else {
815+ newBaseQueueLast. next = ( newBaseQueueFirst : any ) ;
791816 }
792817
793818 // Mark that the fiber performed work, but only if the new state is
@@ -797,8 +822,8 @@ function updateReducer<S, I, A>(
797822 }
798823
799824 hook . memoizedState = newState ;
800- hook . baseUpdate = newBaseUpdate ;
801825 hook . baseState = newBaseState ;
826+ hook . baseQueue = newBaseQueueLast ;
802827
803828 queue . lastRenderedState = newState ;
804829 }
@@ -816,7 +841,7 @@ function mountState<S>(
816841 }
817842 hook . memoizedState = hook . baseState = initialState ;
818843 const queue = ( hook . queue = {
819- last : null ,
844+ pending : null ,
820845 dispatch : null ,
821846 lastRenderedReducer : basicStateReducer ,
822847 lastRenderedState : ( initialState : any ) ,
@@ -1233,7 +1258,7 @@ function dispatchAction<S, A>(
12331258 action,
12341259 eagerReducer : null ,
12351260 eagerState : null ,
1236- next : null ,
1261+ next : ( null : any ) ,
12371262 } ;
12381263 if ( __DEV__ ) {
12391264 update . priority = getCurrentPriorityLevel ( ) ;
@@ -1267,27 +1292,23 @@ function dispatchAction<S, A>(
12671292 action,
12681293 eagerReducer : null ,
12691294 eagerState : null ,
1270- next : null ,
1295+ next : ( null : any ) ,
12711296 } ;
12721297
12731298 if ( __DEV__ ) {
12741299 update . priority = getCurrentPriorityLevel ( ) ;
12751300 }
12761301
12771302 // 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) {
12801305 // This is the first update. Create a circular list.
12811306 update . next = update ;
12821307 } 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 ;
12891310 }
1290- queue . last = update ;
1311+ queue.pending = update;
12911312
12921313 if (
12931314 fiber.expirationTime === NoWork &&
0 commit comments