@@ -77,6 +77,7 @@ import {
77
77
warnIfNotCurrentlyActingUpdatesInDev ,
78
78
warnIfNotScopedWithMatchingAct ,
79
79
markSkippedUpdateLanes ,
80
+ isInterleavedUpdate ,
80
81
} from './ReactFiberWorkLoop.old' ;
81
82
82
83
import invariant from 'shared/invariant' ;
@@ -110,6 +111,7 @@ import {
110
111
enqueueUpdate ,
111
112
entangleTransitions ,
112
113
} from './ReactUpdateQueue.old' ;
114
+ import { pushInterleavedQueue } from './ReactFiberInterleavedUpdates.old' ;
113
115
114
116
const { ReactCurrentDispatcher, ReactCurrentBatchConfig} = ReactSharedInternals ;
115
117
@@ -122,8 +124,9 @@ type Update<S, A> = {|
122
124
priority ?: ReactPriorityLevel ,
123
125
| } ;
124
126
125
- type UpdateQueue < S , A > = { |
127
+ export type UpdateQueue < S , A > = { |
126
128
pending : Update < S , A> | null ,
129
+ interleaved : Update < S , A > | null ,
127
130
lanes : Lanes ,
128
131
dispatch : ( A => mixed ) | null ,
129
132
lastRenderedReducer : ( ( S , A ) => S ) | null ,
@@ -657,6 +660,7 @@ function mountReducer<S, I, A>(
657
660
hook.memoizedState = hook.baseState = initialState;
658
661
const queue = (hook.queue = {
659
662
pending : null ,
663
+ interleaved : null ,
660
664
lanes : NoLanes ,
661
665
dispatch : null ,
662
666
lastRenderedReducer : reducer ,
@@ -800,7 +804,22 @@ function updateReducer<S, I, A>(
800
804
queue.lastRenderedState = newState;
801
805
}
802
806
803
- if ( baseQueue === null ) {
807
+ // Interleaved updates are stored on a separate queue. We aren't going to
808
+ // process them during this render, but we do need to track which lanes
809
+ // are remaining.
810
+ const lastInterleaved = queue . interleaved ;
811
+ if ( lastInterleaved !== null ) {
812
+ let interleaved = lastInterleaved ;
813
+ do {
814
+ const interleavedLane = interleaved . lane ;
815
+ currentlyRenderingFiber . lanes = mergeLanes (
816
+ currentlyRenderingFiber . lanes ,
817
+ interleavedLane ,
818
+ ) ;
819
+ markSkippedUpdateLanes ( interleavedLane ) ;
820
+ interleaved = ( ( interleaved : any ) . next : Update < S , A > ) ;
821
+ } while ( interleaved !== lastInterleaved ) ;
822
+ } else if ( baseQueue === null ) {
804
823
// `queue.lanes` is used for entangling transitions. We can set it back to
805
824
// zero once the queue is empty.
806
825
queue. lanes = NoLanes ;
@@ -1132,6 +1151,7 @@ function useMutableSource<Source, Snapshot>(
1132
1151
// including any interleaving updates that occur.
1133
1152
const newQueue = {
1134
1153
pending : null ,
1154
+ interleaved : null ,
1135
1155
lanes : NoLanes ,
1136
1156
dispatch : null ,
1137
1157
lastRenderedReducer : basicStateReducer ,
@@ -1188,6 +1208,7 @@ function mountState<S>(
1188
1208
hook.memoizedState = hook.baseState = initialState;
1189
1209
const queue = (hook.queue = {
1190
1210
pending : null ,
1211
+ interleaved : null ,
1191
1212
lanes : NoLanes ,
1192
1213
dispatch : null ,
1193
1214
lastRenderedReducer : basicStateReducer ,
@@ -1869,7 +1890,7 @@ function refreshCache<T>(fiber: Fiber, seedKey: ?() => T, seedValue: T) {
1869
1890
cache : seededCache ,
1870
1891
} ;
1871
1892
refreshUpdate . payload = payload ;
1872
- enqueueUpdate ( provider , refreshUpdate ) ;
1893
+ enqueueUpdate ( provider , refreshUpdate , lane ) ;
1873
1894
return ;
1874
1895
}
1875
1896
}
@@ -1904,17 +1925,6 @@ function dispatchAction<S, A>(
1904
1925
next : ( null : any ) ,
1905
1926
} ;
1906
1927
1907
- // Append the update to the end of the list.
1908
- const pending = queue.pending;
1909
- if (pending === null) {
1910
- // This is the first update. Create a circular list.
1911
- update . next = update ;
1912
- } else {
1913
- update . next = pending . next ;
1914
- pending . next = update ;
1915
- }
1916
- queue.pending = update;
1917
-
1918
1928
const alternate = fiber.alternate;
1919
1929
if (
1920
1930
fiber === currentlyRenderingFiber ||
@@ -1924,7 +1934,41 @@ function dispatchAction<S, A>(
1924
1934
// queue -> linked list of updates. After this render pass, we'll restart
1925
1935
// and apply the stashed updates on top of the work-in-progress hook.
1926
1936
didScheduleRenderPhaseUpdateDuringThisPass = didScheduleRenderPhaseUpdate = true ;
1937
+ const pending = queue . pending ;
1938
+ if ( pending === null ) {
1939
+ // This is the first update. Create a circular list.
1940
+ update. next = update ;
1941
+ } else {
1942
+ update . next = pending . next ;
1943
+ pending . next = update ;
1944
+ }
1945
+ queue.pending = update;
1927
1946
} else {
1947
+ if ( isInterleavedUpdate ( fiber , lane ) ) {
1948
+ const interleaved = queue . interleaved ;
1949
+ if ( interleaved === null ) {
1950
+ // This is the first update. Create a circular list.
1951
+ update. next = update ;
1952
+ // At the end of the current render, this queue's interleaved updates will
1953
+ // be transfered to the pending queue.
1954
+ pushInterleavedQueue ( queue ) ;
1955
+ } else {
1956
+ update . next = interleaved . next ;
1957
+ interleaved . next = update ;
1958
+ }
1959
+ queue.interleaved = update;
1960
+ } else {
1961
+ const pending = queue . pending ;
1962
+ if ( pending === null ) {
1963
+ // This is the first update. Create a circular list.
1964
+ update. next = update ;
1965
+ } else {
1966
+ update . next = pending . next ;
1967
+ pending . next = update ;
1968
+ }
1969
+ queue.pending = update;
1970
+ }
1971
+
1928
1972
if (
1929
1973
fiber . lanes === NoLanes &&
1930
1974
( alternate === null || alternate . lanes === NoLanes )
0 commit comments