@@ -20,7 +20,7 @@ import type {ReactPriorityLevel} from './SchedulerWithReactIntegration';
2020
2121import ReactSharedInternals from 'shared/ReactSharedInternals' ;
2222
23- import { NoWork , Sync } from './ReactFiberExpirationTime' ;
23+ import { NoWork } 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> ,
111+ next : Update < S , A> | null ,
112112
113113 priority ?: ReactPriorityLevel ,
114114} ;
115115
116116type UpdateQueue < S , A > = {
117- pending : Update < S , A> | null ,
117+ last : 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- baseQueue : Update < any , any > | null ,
147+ baseUpdate : 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 ,
548547 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 ,
608607 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- pending : null ,
648+ last : 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 . baseQueue === null ) {
706+ if (hook.baseUpdate === queue.last ) {
707707 hook.baseState = newState;
708708 }
709709
@@ -715,55 +715,42 @@ function updateReducer<S, I, A>(
715715 return [hook.memoizedState, dispatch];
716716 }
717717
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 ;
734732 }
735- current.baseQueue = baseQueue = pendingQueue;
736- queue.pending = null;
733+ first = baseUpdate . next ;
734+ } else {
735+ first = last !== null ? last . next : null ;
737736 }
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 ;
744739 let newBaseState = null ;
745- let newBaseQueueFirst = null ;
746- let newBaseQueueLast = null ;
740+ let newBaseUpdate = null ;
741+ let prevUpdate = baseUpdate ;
747742 let update = first ;
743+ let didSkip = false ;
748744 do {
749745 const updateExpirationTime = update . expirationTime ;
750746 if ( updateExpirationTime < renderExpirationTime ) {
751747 // Priority is insufficient. Skip this update. If this is the first
752748 // skipped update, the previous update/state is the new base
753749 // 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 ;
764753 newBaseState = newState ;
765- } else {
766- newBaseQueueLast = newBaseQueueLast . next = clone ;
767754 }
768755 // Update the remaining priority in the queue.
769756 if ( updateExpirationTime > currentlyRenderingFiber . expirationTime ) {
@@ -773,18 +760,6 @@ function updateReducer<S, I, A>(
773760 } else {
774761 // This update does have sufficient priority.
775762
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-
788763 // Mark the event time of this update as relevant to this render pass.
789764 // TODO: This should ideally use the true event time of this update rather than
790765 // its priority which is a derived and not reverseable value.
@@ -806,13 +781,13 @@ function updateReducer<S, I, A>(
806781 newState = reducer ( newState , action) ;
807782 }
808783 }
784+ prevUpdate = update ;
809785 update = update . next ;
810786 } while ( update !== null && update !== first ) ;
811787
812- if ( newBaseQueueLast === null ) {
788+ if ( ! didSkip ) {
789+ newBaseUpdate = prevUpdate ;
813790 newBaseState = newState ;
814- } else {
815- newBaseQueueLast. next = ( newBaseQueueFirst : any ) ;
816791 }
817792
818793 // Mark that the fiber performed work, but only if the new state is
@@ -822,8 +797,8 @@ function updateReducer<S, I, A>(
822797 }
823798
824799 hook . memoizedState = newState ;
800+ hook . baseUpdate = newBaseUpdate ;
825801 hook . baseState = newBaseState ;
826- hook . baseQueue = newBaseQueueLast ;
827802
828803 queue . lastRenderedState = newState ;
829804 }
@@ -841,7 +816,7 @@ function mountState<S>(
841816 }
842817 hook . memoizedState = hook . baseState = initialState ;
843818 const queue = ( hook . queue = {
844- pending : null ,
819+ last : null ,
845820 dispatch : null ,
846821 lastRenderedReducer : basicStateReducer ,
847822 lastRenderedState : ( initialState : any ) ,
@@ -1258,7 +1233,7 @@ function dispatchAction<S, A>(
12581233 action,
12591234 eagerReducer : null ,
12601235 eagerState : null ,
1261- next : ( null : any ) ,
1236+ next : null ,
12621237 } ;
12631238 if ( __DEV__ ) {
12641239 update . priority = getCurrentPriorityLevel ( ) ;
@@ -1292,23 +1267,27 @@ function dispatchAction<S, A>(
12921267 action,
12931268 eagerReducer : null ,
12941269 eagerState : null ,
1295- next : ( null : any ) ,
1270+ next : null ,
12961271 } ;
12971272
12981273 if ( __DEV__ ) {
12991274 update . priority = getCurrentPriorityLevel ( ) ;
13001275 }
13011276
13021277 // 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) {
13051280 // This is the first update. Create a circular list.
13061281 update . next = update ;
13071282 } 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;
13101289 }
1311- queue.pending = update;
1290+ queue . last = update ;
13121291
13131292 if (
13141293 fiber . expirationTime === NoWork &&
0 commit comments