@samitouri / QOS-React-2 / commits / d9fb383d6f

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) {