Extract queueing logic into shared functions (#22452)
As a follow up to #22445, this extracts the queueing logic that is shared between `dispatchSetState` and `dispatchReducerAction` into separate functions. It likely doesn't save any bytes since these will get inlined, anyway, but it does make the flow a bit easier to follow.
Andrew Clark committed
Sep 28, 2021 at 15:05 UTC
d9fb383d6f627bf3f6e53ec7b14ba4d1260959d5
2 files changed
+214
-278
packages/react-reconciler/src/ReactFiberHooks.new.js
+107
-139
@@ -113,9 +113,9 @@ import {logStateUpdateScheduled} from './DebugTracing';
113
import {markStateUpdateScheduled} from './SchedulingProfiler';
114
import {CacheContext} from './ReactFiberCacheComponent.new';
115
import {
116
- createUpdate,
117
- enqueueUpdate,
118
- entangleTransitions,
116
+ createUpdate as createLegacyQueueUpdate,
117
+ enqueueUpdate as enqueueLegacyQueueUpdate,
118
+ entangleTransitions as entangleLegacyQueueTransitions,
119
} from './ReactUpdateQueue.new';
120
import {pushInterleavedQueue} from './ReactFiberInterleavedUpdates.new';
121
import {warnOnSubscriptionInsideStartTransition} from 'shared/ReactFeatureFlags';
@@ -2125,7 +2125,7 @@ function refreshCache<T>(fiber: Fiber, seedKey: ?() => T, seedValue: T) {
2125
const eventTime = requestEventTime();
2126
const root = scheduleUpdateOnFiber(provider, lane, eventTime);
2127
if (root !== null) {
2128
- entangleTransitions(root, provider, lane);
2128
+ entangleLegacyQueueTransitions(root, provider, lane);
2129
}
2130
2131
const seededCache = new Map();
@@ -2136,12 +2136,12 @@ function refreshCache<T>(fiber: Fiber, seedKey: ?() => T, seedValue: T) {
2136
}
2137
2138
// Schedule an update on the cache boundary to trigger a refresh.
2139
- const refreshUpdate = createUpdate(eventTime, lane);
2139
+ const refreshUpdate = createLegacyQueueUpdate(eventTime, lane);
2140
const payload = {
2141
cache: seededCache,
2142
};
2143
refreshUpdate.payload = payload;
2144
- enqueueUpdate(provider, refreshUpdate, lane);
2144
+ enqueueLegacyQueueUpdate(provider, refreshUpdate, lane);
2145
return;
2146
}
2147
}
@@ -2165,7 +2165,6 @@ function dispatchReducerAction<S, A>(
2165
}
2166
}
2167
2168
- const eventTime = requestEventTime();
2168
const lane = requestUpdateLane(fiber);
2169
2170
const update: Update<S, A> = {
@@ -2176,49 +2175,10 @@ function dispatchReducerAction<S, A>(
2175
next: (null: any),
2176
};
2177
2179
- const alternate = fiber.alternate;
2180
- if (
2181
- fiber === currentlyRenderingFiber ||
2182
- (alternate !== null && alternate === currentlyRenderingFiber)
2183
- ) {
2184
- // This is a render phase update. Stash it in a lazily-created map of
2185
- // queue -> linked list of updates. After this render pass, we'll restart
2186
- // and apply the stashed updates on top of the work-in-progress hook.
2187
- didScheduleRenderPhaseUpdateDuringThisPass = didScheduleRenderPhaseUpdate = true;
2188
- const pending = queue.pending;
2189
- if (pending === null) {
2190
- // This is the first update. Create a circular list.
2191
- update.next = update;
2192
- } else {
2193
- update.next = pending.next;
2194
- pending.next = update;
2195
- }
2196
- queue.pending = update;
2178
+ if (isRenderPhaseUpdate(fiber)) {
2179
+ enqueueRenderPhaseUpdate(queue, update);
2180
} else {
2198
- if (isInterleavedUpdate(fiber, lane)) {
2199
- const interleaved = queue.interleaved;
2200
- if (interleaved === null) {
2201
- // This is the first update. Create a circular list.
2202
- update.next = update;
2203
- // At the end of the current render, this queue's interleaved updates will
2204
- // be transferred to the pending queue.
2205
- pushInterleavedQueue(queue);
2206
- } else {
2207
- update.next = interleaved.next;
2208
- interleaved.next = update;
2209
- }
2210
- queue.interleaved = update;
2211
- } else {
2212
- const pending = queue.pending;
2213
- if (pending === null) {
2214
- // This is the first update. Create a circular list.
2215
- update.next = update;
2216
- } else {
2217
- update.next = pending.next;
2218
- pending.next = update;
2219
- }
2220
- queue.pending = update;
2221
- }
2181
+ enqueueUpdate(fiber, queue, update, lane);
2182
2183
if (__DEV__) {
2184
// $FlowExpectedError - jest isn't a global, and isn't recognized outside of tests
@@ -2226,40 +2186,14 @@ function dispatchReducerAction<S, A>(
2186
warnIfNotCurrentlyActingUpdatesInDev(fiber);
2187
}
2188
}
2189
+ const eventTime = requestEventTime();
2190
const root = scheduleUpdateOnFiber(fiber, lane, eventTime);
2230
-
2231
- if (isTransitionLane(lane) && root !== null) {
2232
- let queueLanes = queue.lanes;
2233
-
2234
- // If any entangled lanes are no longer pending on the root, then they
2235
- // must have finished. We can remove them from the shared queue, which
2236
- // represents a superset of the actually pending lanes. In some cases we
2237
- // may entangle more than we need to, but that's OK. In fact it's worse if
2238
- // we *don't* entangle when we should.
2239
- queueLanes = intersectLanes(queueLanes, root.pendingLanes);
2240
-
2241
- // Entangle the new transition lane with the other transition lanes.
2242
- const newQueueLanes = mergeLanes(queueLanes, lane);
2243
- queue.lanes = newQueueLanes;
2244
- // Even if queue.lanes already include lane, we don't know for certain if
2245
- // the lane finished since the last time we entangled it. So we need to
2246
- // entangle it again, just to be sure.
2247
- markRootEntangled(root, newQueueLanes);
2248
- }
2249
- }
2250
-
2251
- if (__DEV__) {
2252
- if (enableDebugTracing) {
2253
- if (fiber.mode & DebugTracingMode) {
2254
- const name = getComponentNameFromFiber(fiber) || 'Unknown';
2255
- logStateUpdateScheduled(name, lane, action);
2256
- }
2191
+ if (root !== null) {
2192
+ entangleTransitionUpdate(root, queue, lane);
2193
}
2194
}
2195
2260
- if (enableSchedulingProfiler) {
2261
- markStateUpdateScheduled(fiber, lane);
2262
- }
2196
+ markUpdateInDevTools(fiber, lane, action);
2197
}
2198
2199
function dispatchSetState<S, A>(
@@ -2277,7 +2211,6 @@ function dispatchSetState<S, A>(
2211
}
2212
}
2213
2280
- const eventTime = requestEventTime();
2214
const lane = requestUpdateLane(fiber);
2215
2216
const update: Update<S, A> = {
@@ -2288,50 +2221,12 @@ function dispatchSetState<S, A>(
2221
next: (null: any),
2222
};
2223
2291
- const alternate = fiber.alternate;
2292
- if (
2293
- fiber === currentlyRenderingFiber ||
2294
- (alternate !== null && alternate === currentlyRenderingFiber)
2295
- ) {
2296
- // This is a render phase update. Stash it in a lazily-created map of
2297
- // queue -> linked list of updates. After this render pass, we'll restart
2298
- // and apply the stashed updates on top of the work-in-progress hook.
2299
- didScheduleRenderPhaseUpdateDuringThisPass = didScheduleRenderPhaseUpdate = true;
2300
- const pending = queue.pending;
2301
- if (pending === null) {
2302
- // This is the first update. Create a circular list.
2303
- update.next = update;
2304
- } else {
2305
- update.next = pending.next;
2306
- pending.next = update;
2307
- }
2308
- queue.pending = update;
2224
+ if (isRenderPhaseUpdate(fiber)) {
2225
+ enqueueRenderPhaseUpdate(queue, update);
2226
} else {
2310
- if (isInterleavedUpdate(fiber, lane)) {
2311
- const interleaved = queue.interleaved;
2312
- if (interleaved === null) {
2313
- // This is the first update. Create a circular list.
2314
- update.next = update;
2315
- // At the end of the current render, this queue's interleaved updates will
2316
- // be transferred to the pending queue.
2317
- pushInterleavedQueue(queue);
2318
- } else {
2319
- update.next = interleaved.next;
2320
- interleaved.next = update;
2321
- }
2322
- queue.interleaved = update;
2323
- } else {
2324
- const pending = queue.pending;
2325
- if (pending === null) {
2326
- // This is the first update. Create a circular list.
2327
- update.next = update;
2328
- } else {
2329
- update.next = pending.next;
2330
- pending.next = update;
2331
- }
2332
- queue.pending = update;
2333
- }
2227
+ enqueueUpdate(fiber, queue, update, lane);
2228
2229
+ const alternate = fiber.alternate;
2230
if (
2231
fiber.lanes === NoLanes &&
2232
(alternate === null || alternate.lanes === NoLanes)
@@ -2377,28 +2272,101 @@ function dispatchSetState<S, A>(
2272
warnIfNotCurrentlyActingUpdatesInDev(fiber);
2273
}
2274
}
2275
+ const eventTime = requestEventTime();
2276
const root = scheduleUpdateOnFiber(fiber, lane, eventTime);
2277
+ if (root !== null) {
2278
+ entangleTransitionUpdate(root, queue, lane);
2279
+ }
2280
+ }
2281
+
2282
+ markUpdateInDevTools(fiber, lane, action);
2283
+}
2284
+
2285
+function isRenderPhaseUpdate(fiber: Fiber) {
2286
+ const alternate = fiber.alternate;
2287
+ return (
2288
+ fiber === currentlyRenderingFiber ||
2289
+ (alternate !== null && alternate === currentlyRenderingFiber)
2290
+ );
2291
+}
2292
+
2293
+function enqueueRenderPhaseUpdate<S, A>(
2294
+ queue: UpdateQueue<S, A>,
2295
+ update: Update<S, A>,
2296
+) {
2297
+ // This is a render phase update. Stash it in a lazily-created map of
2298
+ // queue -> linked list of updates. After this render pass, we'll restart
2299
+ // and apply the stashed updates on top of the work-in-progress hook.
2300
+ didScheduleRenderPhaseUpdateDuringThisPass = didScheduleRenderPhaseUpdate = true;
2301
+ const pending = queue.pending;
2302
+ if (pending === null) {
2303
+ // This is the first update. Create a circular list.
2304
+ update.next = update;
2305
+ } else {
2306
+ update.next = pending.next;
2307
+ pending.next = update;
2308
+ }
2309
+ queue.pending = update;
2310
+}
2311
2382
- if (isTransitionLane(lane) && root !== null) {
2383
- let queueLanes = queue.lanes;
2384
-
2385
- // If any entangled lanes are no longer pending on the root, then they
2386
- // must have finished. We can remove them from the shared queue, which
2387
- // represents a superset of the actually pending lanes. In some cases we
2388
- // may entangle more than we need to, but that's OK. In fact it's worse if
2389
- // we *don't* entangle when we should.
2390
- queueLanes = intersectLanes(queueLanes, root.pendingLanes);
2391
-
2392
- // Entangle the new transition lane with the other transition lanes.
2393
- const newQueueLanes = mergeLanes(queueLanes, lane);
2394
- queue.lanes = newQueueLanes;
2395
- // Even if queue.lanes already include lane, we don't know for certain if
2396
- // the lane finished since the last time we entangled it. So we need to
2397
- // entangle it again, just to be sure.
2398
- markRootEntangled(root, newQueueLanes);
2312
+function enqueueUpdate<S, A>(
2313
+ fiber: Fiber,
2314
+ queue: UpdateQueue<S, A>,
2315
+ update: Update<S, A>,
2316
+ lane: Lane,
2317
+) {
2318
+ if (isInterleavedUpdate(fiber, lane)) {
2319
+ const interleaved = queue.interleaved;
2320
+ if (interleaved === null) {
2321
+ // This is the first update. Create a circular list.
2322
+ update.next = update;
2323
+ // At the end of the current render, this queue's interleaved updates will
2324
+ // be transferred to the pending queue.
2325
+ pushInterleavedQueue(queue);
2326
+ } else {
2327
+ update.next = interleaved.next;
2328
+ interleaved.next = update;
2329
+ }
2330
+ queue.interleaved = update;
2331
+ } else {
2332
+ const pending = queue.pending;
2333
+ if (pending === null) {
2334
+ // This is the first update. Create a circular list.
2335
+ update.next = update;
2336
+ } else {
2337
+ update.next = pending.next;
2338
+ pending.next = update;
2339
}
2340
+ queue.pending = update;
2341
+ }
2342
+}
2343
+
2344
+function entangleTransitionUpdate<S, A>(
2345
+ root: FiberRoot,
2346
+ queue: UpdateQueue<S, A>,
2347
+ lane: Lane,
2348
+) {
2349
+ if (isTransitionLane(lane)) {
2350
+ let queueLanes = queue.lanes;
2351
+
2352
+ // If any entangled lanes are no longer pending on the root, then they
2353
+ // must have finished. We can remove them from the shared queue, which
2354
+ // represents a superset of the actually pending lanes. In some cases we
2355
+ // may entangle more than we need to, but that's OK. In fact it's worse if
2356
+ // we *don't* entangle when we should.
2357
+ queueLanes = intersectLanes(queueLanes, root.pendingLanes);
2358
+
2359
+ // Entangle the new transition lane with the other transition lanes.
2360
+ const newQueueLanes = mergeLanes(queueLanes, lane);
2361
+ queue.lanes = newQueueLanes;
2362
+ // Even if queue.lanes already include lane, we don't know for certain if
2363
+ // the lane finished since the last time we entangled it. So we need to
2364
+ // entangle it again, just to be sure.
2365
+ markRootEntangled(root, newQueueLanes);
2366
}
2367
+}
2368
2369
+function markUpdateInDevTools(fiber, lane, action) {
2370
if (__DEV__) {
2371
if (enableDebugTracing) {
2372
if (fiber.mode & DebugTracingMode) {
packages/react-reconciler/src/ReactFiberHooks.old.js
+107
-139
@@ -113,9 +113,9 @@ import {logStateUpdateScheduled} from './DebugTracing';
113
import {markStateUpdateScheduled} from './SchedulingProfiler';
114
import {CacheContext} from './ReactFiberCacheComponent.old';
115
import {
116
- createUpdate,
117
- enqueueUpdate,
118
- entangleTransitions,
116
+ createUpdate as createLegacyQueueUpdate,
117
+ enqueueUpdate as enqueueLegacyQueueUpdate,
118
+ entangleTransitions as entangleLegacyQueueTransitions,
119
} from './ReactUpdateQueue.old';
120
import {pushInterleavedQueue} from './ReactFiberInterleavedUpdates.old';
121
import {warnOnSubscriptionInsideStartTransition} from 'shared/ReactFeatureFlags';
@@ -2125,7 +2125,7 @@ function refreshCache<T>(fiber: Fiber, seedKey: ?() => T, seedValue: T) {
2125
const eventTime = requestEventTime();
2126
const root = scheduleUpdateOnFiber(provider, lane, eventTime);
2127
if (root !== null) {
2128
- entangleTransitions(root, provider, lane);
2128
+ entangleLegacyQueueTransitions(root, provider, lane);
2129
}
2130
2131
const seededCache = new Map();
@@ -2136,12 +2136,12 @@ function refreshCache<T>(fiber: Fiber, seedKey: ?() => T, seedValue: T) {
2136
}
2137
2138
// Schedule an update on the cache boundary to trigger a refresh.
2139
- const refreshUpdate = createUpdate(eventTime, lane);
2139
+ const refreshUpdate = createLegacyQueueUpdate(eventTime, lane);
2140
const payload = {
2141
cache: seededCache,
2142
};
2143
refreshUpdate.payload = payload;
2144
- enqueueUpdate(provider, refreshUpdate, lane);
2144
+ enqueueLegacyQueueUpdate(provider, refreshUpdate, lane);
2145
return;
2146
}
2147
}
@@ -2165,7 +2165,6 @@ function dispatchReducerAction<S, A>(
2165
}
2166
}
2167
2168
- const eventTime = requestEventTime();
2168
const lane = requestUpdateLane(fiber);
2169
2170
const update: Update<S, A> = {
@@ -2176,49 +2175,10 @@ function dispatchReducerAction<S, A>(
2175
next: (null: any),
2176
};
2177
2179
- const alternate = fiber.alternate;
2180
- if (
2181
- fiber === currentlyRenderingFiber ||
2182
- (alternate !== null && alternate === currentlyRenderingFiber)
2183
- ) {
2184
- // This is a render phase update. Stash it in a lazily-created map of
2185
- // queue -> linked list of updates. After this render pass, we'll restart
2186
- // and apply the stashed updates on top of the work-in-progress hook.
2187
- didScheduleRenderPhaseUpdateDuringThisPass = didScheduleRenderPhaseUpdate = true;
2188
- const pending = queue.pending;
2189
- if (pending === null) {
2190
- // This is the first update. Create a circular list.
2191
- update.next = update;
2192
- } else {
2193
- update.next = pending.next;
2194
- pending.next = update;
2195
- }
2196
- queue.pending = update;
2178
+ if (isRenderPhaseUpdate(fiber)) {
2179
+ enqueueRenderPhaseUpdate(queue, update);
2180
} else {
2198
- if (isInterleavedUpdate(fiber, lane)) {
2199
- const interleaved = queue.interleaved;
2200
- if (interleaved === null) {
2201
- // This is the first update. Create a circular list.
2202
- update.next = update;
2203
- // At the end of the current render, this queue's interleaved updates will
2204
- // be transferred to the pending queue.
2205
- pushInterleavedQueue(queue);
2206
- } else {
2207
- update.next = interleaved.next;
2208
- interleaved.next = update;
2209
- }
2210
- queue.interleaved = update;
2211
- } else {
2212
- const pending = queue.pending;
2213
- if (pending === null) {
2214
- // This is the first update. Create a circular list.
2215
- update.next = update;
2216
- } else {
2217
- update.next = pending.next;
2218
- pending.next = update;
2219
- }
2220
- queue.pending = update;
2221
- }
2181
+ enqueueUpdate(fiber, queue, update, lane);
2182
2183
if (__DEV__) {
2184
// $FlowExpectedError - jest isn't a global, and isn't recognized outside of tests
@@ -2226,40 +2186,14 @@ function dispatchReducerAction<S, A>(
2186
warnIfNotCurrentlyActingUpdatesInDev(fiber);
2187
}
2188
}
2189
+ const eventTime = requestEventTime();
2190
const root = scheduleUpdateOnFiber(fiber, lane, eventTime);
2230
-
2231
- if (isTransitionLane(lane) && root !== null) {
2232
- let queueLanes = queue.lanes;
2233
-
2234
- // If any entangled lanes are no longer pending on the root, then they
2235
- // must have finished. We can remove them from the shared queue, which
2236
- // represents a superset of the actually pending lanes. In some cases we
2237
- // may entangle more than we need to, but that's OK. In fact it's worse if
2238
- // we *don't* entangle when we should.
2239
- queueLanes = intersectLanes(queueLanes, root.pendingLanes);
2240
-
2241
- // Entangle the new transition lane with the other transition lanes.
2242
- const newQueueLanes = mergeLanes(queueLanes, lane);
2243
- queue.lanes = newQueueLanes;
2244
- // Even if queue.lanes already include lane, we don't know for certain if
2245
- // the lane finished since the last time we entangled it. So we need to
2246
- // entangle it again, just to be sure.
2247
- markRootEntangled(root, newQueueLanes);
2248
- }
2249
- }
2250
-
2251
- if (__DEV__) {
2252
- if (enableDebugTracing) {
2253
- if (fiber.mode & DebugTracingMode) {
2254
- const name = getComponentNameFromFiber(fiber) || 'Unknown';
2255
- logStateUpdateScheduled(name, lane, action);
2256
- }
2191
+ if (root !== null) {
2192
+ entangleTransitionUpdate(root, queue, lane);
2193
}
2194
}
2195
2260
- if (enableSchedulingProfiler) {
2261
- markStateUpdateScheduled(fiber, lane);
2262
- }
2196
+ markUpdateInDevTools(fiber, lane, action);
2197
}
2198
2199
function dispatchSetState<S, A>(
@@ -2277,7 +2211,6 @@ function dispatchSetState<S, A>(
2211
}
2212
}
2213
2280
- const eventTime = requestEventTime();
2214
const lane = requestUpdateLane(fiber);
2215
2216
const update: Update<S, A> = {
@@ -2288,50 +2221,12 @@ function dispatchSetState<S, A>(
2221
next: (null: any),
2222
};
2223
2291
- const alternate = fiber.alternate;
2292
- if (
2293
- fiber === currentlyRenderingFiber ||
2294
- (alternate !== null && alternate === currentlyRenderingFiber)
2295
- ) {
2296
- // This is a render phase update. Stash it in a lazily-created map of
2297
- // queue -> linked list of updates. After this render pass, we'll restart
2298
- // and apply the stashed updates on top of the work-in-progress hook.
2299
- didScheduleRenderPhaseUpdateDuringThisPass = didScheduleRenderPhaseUpdate = true;
2300
- const pending = queue.pending;
2301
- if (pending === null) {
2302
- // This is the first update. Create a circular list.
2303
- update.next = update;
2304
- } else {
2305
- update.next = pending.next;
2306
- pending.next = update;
2307
- }
2308
- queue.pending = update;
2224
+ if (isRenderPhaseUpdate(fiber)) {
2225
+ enqueueRenderPhaseUpdate(queue, update);
2226
} else {
2310
- if (isInterleavedUpdate(fiber, lane)) {
2311
- const interleaved = queue.interleaved;
2312
- if (interleaved === null) {
2313
- // This is the first update. Create a circular list.
2314
- update.next = update;
2315
- // At the end of the current render, this queue's interleaved updates will
2316
- // be transferred to the pending queue.
2317
- pushInterleavedQueue(queue);
2318
- } else {
2319
- update.next = interleaved.next;
2320
- interleaved.next = update;
2321
- }
2322
- queue.interleaved = update;
2323
- } else {
2324
- const pending = queue.pending;
2325
- if (pending === null) {
2326
- // This is the first update. Create a circular list.
2327
- update.next = update;
2328
- } else {
2329
- update.next = pending.next;
2330
- pending.next = update;
2331
- }
2332
- queue.pending = update;
2333
- }
2227
+ enqueueUpdate(fiber, queue, update, lane);
2228
2229
+ const alternate = fiber.alternate;
2230
if (
2231
fiber.lanes === NoLanes &&
2232
(alternate === null || alternate.lanes === NoLanes)
@@ -2377,28 +2272,101 @@ function dispatchSetState<S, A>(
2272
warnIfNotCurrentlyActingUpdatesInDev(fiber);
2273
}
2274
}
2275
+ const eventTime = requestEventTime();
2276
const root = scheduleUpdateOnFiber(fiber, lane, eventTime);
2277
+ if (root !== null) {
2278
+ entangleTransitionUpdate(root, queue, lane);
2279
+ }
2280
+ }
2281
+
2282
+ markUpdateInDevTools(fiber, lane, action);
2283
+}
2284
+
2285
+function isRenderPhaseUpdate(fiber: Fiber) {
2286
+ const alternate = fiber.alternate;
2287
+ return (
2288
+ fiber === currentlyRenderingFiber ||
2289
+ (alternate !== null && alternate === currentlyRenderingFiber)
2290
+ );
2291
+}
2292
+
2293
+function enqueueRenderPhaseUpdate<S, A>(
2294
+ queue: UpdateQueue<S, A>,
2295
+ update: Update<S, A>,
2296
+) {
2297
+ // This is a render phase update. Stash it in a lazily-created map of
2298
+ // queue -> linked list of updates. After this render pass, we'll restart
2299
+ // and apply the stashed updates on top of the work-in-progress hook.
2300
+ didScheduleRenderPhaseUpdateDuringThisPass = didScheduleRenderPhaseUpdate = true;
2301
+ const pending = queue.pending;
2302
+ if (pending === null) {
2303
+ // This is the first update. Create a circular list.
2304
+ update.next = update;
2305
+ } else {
2306
+ update.next = pending.next;
2307
+ pending.next = update;
2308
+ }
2309
+ queue.pending = update;
2310
+}
2311
2382
- if (isTransitionLane(lane) && root !== null) {
2383
- let queueLanes = queue.lanes;
2384
-
2385
- // If any entangled lanes are no longer pending on the root, then they
2386
- // must have finished. We can remove them from the shared queue, which
2387
- // represents a superset of the actually pending lanes. In some cases we
2388
- // may entangle more than we need to, but that's OK. In fact it's worse if
2389
- // we *don't* entangle when we should.
2390
- queueLanes = intersectLanes(queueLanes, root.pendingLanes);
2391
-
2392
- // Entangle the new transition lane with the other transition lanes.
2393
- const newQueueLanes = mergeLanes(queueLanes, lane);
2394
- queue.lanes = newQueueLanes;
2395
- // Even if queue.lanes already include lane, we don't know for certain if
2396
- // the lane finished since the last time we entangled it. So we need to
2397
- // entangle it again, just to be sure.
2398
- markRootEntangled(root, newQueueLanes);
2312
+function enqueueUpdate<S, A>(
2313
+ fiber: Fiber,
2314
+ queue: UpdateQueue<S, A>,
2315
+ update: Update<S, A>,
2316
+ lane: Lane,
2317
+) {
2318
+ if (isInterleavedUpdate(fiber, lane)) {
2319
+ const interleaved = queue.interleaved;
2320
+ if (interleaved === null) {
2321
+ // This is the first update. Create a circular list.
2322
+ update.next = update;
2323
+ // At the end of the current render, this queue's interleaved updates will
2324
+ // be transferred to the pending queue.
2325
+ pushInterleavedQueue(queue);
2326
+ } else {
2327
+ update.next = interleaved.next;
2328
+ interleaved.next = update;
2329
+ }
2330
+ queue.interleaved = update;
2331
+ } else {
2332
+ const pending = queue.pending;
2333
+ if (pending === null) {
2334
+ // This is the first update. Create a circular list.
2335
+ update.next = update;
2336
+ } else {
2337
+ update.next = pending.next;
2338
+ pending.next = update;
2339
}
2340
+ queue.pending = update;
2341
+ }
2342
+}
2343
+
2344
+function entangleTransitionUpdate<S, A>(
2345
+ root: FiberRoot,
2346
+ queue: UpdateQueue<S, A>,
2347
+ lane: Lane,
2348
+) {
2349
+ if (isTransitionLane(lane)) {
2350
+ let queueLanes = queue.lanes;
2351
+
2352
+ // If any entangled lanes are no longer pending on the root, then they
2353
+ // must have finished. We can remove them from the shared queue, which
2354
+ // represents a superset of the actually pending lanes. In some cases we
2355
+ // may entangle more than we need to, but that's OK. In fact it's worse if
2356
+ // we *don't* entangle when we should.
2357
+ queueLanes = intersectLanes(queueLanes, root.pendingLanes);
2358
+
2359
+ // Entangle the new transition lane with the other transition lanes.
2360
+ const newQueueLanes = mergeLanes(queueLanes, lane);
2361
+ queue.lanes = newQueueLanes;
2362
+ // Even if queue.lanes already include lane, we don't know for certain if
2363
+ // the lane finished since the last time we entangled it. So we need to
2364
+ // entangle it again, just to be sure.
2365
+ markRootEntangled(root, newQueueLanes);
2366
}
2367
+}
2368
2369
+function markUpdateInDevTools(fiber, lane, action) {
2370
if (__DEV__) {
2371
if (enableDebugTracing) {
2372
if (fiber.mode & DebugTracingMode) {