@samitouri / QOS-React-2 / commits / 40eaa22d9a

Remove dependency on Offscreen Fiber updateQueue for React Cache (#23229)

We need to use the Offscreen Fiber's update queue for interaction tracing. This PR removes the optimization that React Cache uses to not need to push and pop the cache in special circumstances and defaults to always pushing and popping the cache as long as there was a previous cache.

Luna Ruan committed Feb 19, 2022 at 10:25 UTC 40eaa22d9af685c239f9d8d42b454d031791e76d
10 files changed +150 -146
packages/react-reconciler/src/ReactFiberBeginWork.new.js
+36 -34
@@ -234,7 +234,7 @@ import {
234 pushRootCachePool,
235 CacheContext,
236 getSuspendedCachePool,
237 - restoreSpawnedCachePool,
237 + pushSpawnedCachePool,
238 getOffscreenDeferredCachePool,
239 } from './ReactFiberCacheComponent.new';
240 import {createCapturedValue} from './ReactCapturedValue';
@@ -635,11 +635,6 @@ function updateOffscreenComponent(
635 const prevState: OffscreenState | null =
636 current !== null ? current.memoizedState : null;
637
638 - // If this is not null, this is a cache pool that was carried over from the
639 - // previous render. We will push this to the cache pool context so that we can
640 - // resume in-flight requests.
641 - let spawnedCachePool: SpawnedCachePool | null = null;
642 -
638 if (
639 nextProps.mode === 'hidden' ||
640 nextProps.mode === 'unstable-defer-without-hiding'
@@ -652,8 +647,16 @@ function updateOffscreenComponent(
647 cachePool: null,
648 };
649 workInProgress.memoizedState = nextState;
650 + if (enableCache) {
651 + // push the cache pool even though we're going to bail out
652 + // because otherwise there'd be a context mismatch
653 + if (current !== null) {
654 + pushSpawnedCachePool(workInProgress, null);
655 + }
656 + }
657 pushRenderLanes(workInProgress, renderLanes);
658 } else if (!includesSomeLane(renderLanes, (OffscreenLane: Lane))) {
659 + let spawnedCachePool: SpawnedCachePool | null = null;
660 // We're hidden, and we're not rendering at Offscreen. We will bail out
661 // and resume this tree later.
662 let nextBaseLanes;
@@ -663,9 +666,6 @@ function updateOffscreenComponent(
666 if (enableCache) {
667 // Save the cache pool so we can resume later.
668 spawnedCachePool = getOffscreenDeferredCachePool();
666 - // We don't need to push to the cache pool because we're about to
667 - // bail out. There won't be a context mismatch because we only pop
668 - // the cache pool if `updateQueue` is non-null.
669 }
670 } else {
671 nextBaseLanes = renderLanes;
@@ -681,6 +681,14 @@ function updateOffscreenComponent(
681 };
682 workInProgress.memoizedState = nextState;
683 workInProgress.updateQueue = null;
684 + if (enableCache) {
685 + // push the cache pool even though we're going to bail out
686 + // because otherwise there'd be a context mismatch
687 + if (current !== null) {
688 + pushSpawnedCachePool(workInProgress, null);
689 + }
690 + }
691 +
692 // We're about to bail out, but we need to push this to the stack anyway
693 // to avoid a push/pop misalignment.
694 pushRenderLanes(workInProgress, nextBaseLanes);
@@ -701,19 +709,6 @@ function updateOffscreenComponent(
709 // This is the second render. The surrounding visible content has already
710 // committed. Now we resume rendering the hidden tree.
711
704 - if (enableCache && prevState !== null) {
705 - // If the render that spawned this one accessed the cache pool, resume
706 - // using the same cache. Unless the parent changed, since that means
707 - // there was a refresh.
708 - const prevCachePool = prevState.cachePool;
709 - if (prevCachePool !== null) {
710 - spawnedCachePool = restoreSpawnedCachePool(
711 - workInProgress,
712 - prevCachePool,
713 - );
714 - }
715 - }
716 -
712 // Rendering at offscreen, so we can clear the base lanes.
713 const nextState: OffscreenState = {
714 baseLanes: NoLanes,
@@ -723,6 +718,14 @@ function updateOffscreenComponent(
718 // Push the lanes that were skipped when we bailed out.
719 const subtreeRenderLanes =
720 prevState !== null ? prevState.baseLanes : renderLanes;
721 + if (enableCache && current !== null) {
722 + // If the render that spawned this one accessed the cache pool, resume
723 + // using the same cache. Unless the parent changed, since that means
724 + // there was a refresh.
725 + const prevCachePool = prevState !== null ? prevState.cachePool : null;
726 + pushSpawnedCachePool(workInProgress, prevCachePool);
727 + }
728 +
729 pushRenderLanes(workInProgress, subtreeRenderLanes);
730 }
731 } else {
@@ -738,12 +741,7 @@ function updateOffscreenComponent(
741 // using the same cache. Unless the parent changed, since that means
742 // there was a refresh.
743 const prevCachePool = prevState.cachePool;
741 - if (prevCachePool !== null) {
742 - spawnedCachePool = restoreSpawnedCachePool(
743 - workInProgress,
744 - prevCachePool,
745 - );
746 - }
744 + pushSpawnedCachePool(workInProgress, prevCachePool);
745 }
746
747 // Since we're not hidden anymore, reset the state
@@ -753,16 +751,19 @@ function updateOffscreenComponent(
751 // special to do. Need to push to the stack regardless, though, to avoid
752 // a push/pop misalignment.
753 subtreeRenderLanes = renderLanes;
754 +
755 + if (enableCache) {
756 + // If the render that spawned this one accessed the cache pool, resume
757 + // using the same cache. Unless the parent changed, since that means
758 + // there was a refresh.
759 + if (current !== null) {
760 + pushSpawnedCachePool(workInProgress, null);
761 + }
762 + }
763 }
764 pushRenderLanes(workInProgress, subtreeRenderLanes);
765 }
766
760 - if (enableCache) {
761 - // If we have a cache pool from a previous render attempt, then this will be
762 - // non-null. We use this to infer whether to push/pop the cache context.
763 - workInProgress.updateQueue = spawnedCachePool;
764 - }
765 -
767 if (enablePersistentOffscreenHostContainer && supportsPersistence) {
768 // In persistent mode, the offscreen children are wrapped in a host node.
769 // TODO: Optimize this to use the OffscreenComponent fiber instead of
@@ -2072,6 +2073,7 @@ function updateSuspenseComponent(current, workInProgress, renderLanes) {
2073
2074 const nextPrimaryChildren = nextProps.children;
2075 const nextFallbackChildren = nextProps.fallback;
2076 +
2077 if (showFallback) {
2078 const fallbackFragment = mountSuspenseFallbackChildren(
2079 workInProgress,
packages/react-reconciler/src/ReactFiberBeginWork.old.js
+36 -34
@@ -234,7 +234,7 @@ import {
234 pushRootCachePool,
235 CacheContext,
236 getSuspendedCachePool,
237 - restoreSpawnedCachePool,
237 + pushSpawnedCachePool,
238 getOffscreenDeferredCachePool,
239 } from './ReactFiberCacheComponent.old';
240 import {createCapturedValue} from './ReactCapturedValue';
@@ -635,11 +635,6 @@ function updateOffscreenComponent(
635 const prevState: OffscreenState | null =
636 current !== null ? current.memoizedState : null;
637
638 - // If this is not null, this is a cache pool that was carried over from the
639 - // previous render. We will push this to the cache pool context so that we can
640 - // resume in-flight requests.
641 - let spawnedCachePool: SpawnedCachePool | null = null;
642 -
638 if (
639 nextProps.mode === 'hidden' ||
640 nextProps.mode === 'unstable-defer-without-hiding'
@@ -652,8 +647,16 @@ function updateOffscreenComponent(
647 cachePool: null,
648 };
649 workInProgress.memoizedState = nextState;
650 + if (enableCache) {
651 + // push the cache pool even though we're going to bail out
652 + // because otherwise there'd be a context mismatch
653 + if (current !== null) {
654 + pushSpawnedCachePool(workInProgress, null);
655 + }
656 + }
657 pushRenderLanes(workInProgress, renderLanes);
658 } else if (!includesSomeLane(renderLanes, (OffscreenLane: Lane))) {
659 + let spawnedCachePool: SpawnedCachePool | null = null;
660 // We're hidden, and we're not rendering at Offscreen. We will bail out
661 // and resume this tree later.
662 let nextBaseLanes;
@@ -663,9 +666,6 @@ function updateOffscreenComponent(
666 if (enableCache) {
667 // Save the cache pool so we can resume later.
668 spawnedCachePool = getOffscreenDeferredCachePool();
666 - // We don't need to push to the cache pool because we're about to
667 - // bail out. There won't be a context mismatch because we only pop
668 - // the cache pool if `updateQueue` is non-null.
669 }
670 } else {
671 nextBaseLanes = renderLanes;
@@ -681,6 +681,14 @@ function updateOffscreenComponent(
681 };
682 workInProgress.memoizedState = nextState;
683 workInProgress.updateQueue = null;
684 + if (enableCache) {
685 + // push the cache pool even though we're going to bail out
686 + // because otherwise there'd be a context mismatch
687 + if (current !== null) {
688 + pushSpawnedCachePool(workInProgress, null);
689 + }
690 + }
691 +
692 // We're about to bail out, but we need to push this to the stack anyway
693 // to avoid a push/pop misalignment.
694 pushRenderLanes(workInProgress, nextBaseLanes);
@@ -701,19 +709,6 @@ function updateOffscreenComponent(
709 // This is the second render. The surrounding visible content has already
710 // committed. Now we resume rendering the hidden tree.
711
704 - if (enableCache && prevState !== null) {
705 - // If the render that spawned this one accessed the cache pool, resume
706 - // using the same cache. Unless the parent changed, since that means
707 - // there was a refresh.
708 - const prevCachePool = prevState.cachePool;
709 - if (prevCachePool !== null) {
710 - spawnedCachePool = restoreSpawnedCachePool(
711 - workInProgress,
712 - prevCachePool,
713 - );
714 - }
715 - }
716 -
712 // Rendering at offscreen, so we can clear the base lanes.
713 const nextState: OffscreenState = {
714 baseLanes: NoLanes,
@@ -723,6 +718,14 @@ function updateOffscreenComponent(
718 // Push the lanes that were skipped when we bailed out.
719 const subtreeRenderLanes =
720 prevState !== null ? prevState.baseLanes : renderLanes;
721 + if (enableCache && current !== null) {
722 + // If the render that spawned this one accessed the cache pool, resume
723 + // using the same cache. Unless the parent changed, since that means
724 + // there was a refresh.
725 + const prevCachePool = prevState !== null ? prevState.cachePool : null;
726 + pushSpawnedCachePool(workInProgress, prevCachePool);
727 + }
728 +
729 pushRenderLanes(workInProgress, subtreeRenderLanes);
730 }
731 } else {
@@ -738,12 +741,7 @@ function updateOffscreenComponent(
741 // using the same cache. Unless the parent changed, since that means
742 // there was a refresh.
743 const prevCachePool = prevState.cachePool;
741 - if (prevCachePool !== null) {
742 - spawnedCachePool = restoreSpawnedCachePool(
743 - workInProgress,
744 - prevCachePool,
745 - );
746 - }
744 + pushSpawnedCachePool(workInProgress, prevCachePool);
745 }
746
747 // Since we're not hidden anymore, reset the state
@@ -753,16 +751,19 @@ function updateOffscreenComponent(
751 // special to do. Need to push to the stack regardless, though, to avoid
752 // a push/pop misalignment.
753 subtreeRenderLanes = renderLanes;
754 +
755 + if (enableCache) {
756 + // If the render that spawned this one accessed the cache pool, resume
757 + // using the same cache. Unless the parent changed, since that means
758 + // there was a refresh.
759 + if (current !== null) {
760 + pushSpawnedCachePool(workInProgress, null);
761 + }
762 + }
763 }
764 pushRenderLanes(workInProgress, subtreeRenderLanes);
765 }
766
760 - if (enableCache) {
761 - // If we have a cache pool from a previous render attempt, then this will be
762 - // non-null. We use this to infer whether to push/pop the cache context.
763 - workInProgress.updateQueue = spawnedCachePool;
764 - }
765 -
767 if (enablePersistentOffscreenHostContainer && supportsPersistence) {
768 // In persistent mode, the offscreen children are wrapped in a host node.
769 // TODO: Optimize this to use the OffscreenComponent fiber instead of
@@ -2072,6 +2073,7 @@ function updateSuspenseComponent(current, workInProgress, renderLanes) {
2073
2074 const nextPrimaryChildren = nextProps.children;
2075 const nextFallbackChildren = nextProps.fallback;
2076 +
2077 if (showFallback) {
2078 const fallbackFragment = mountSuspenseFallbackChildren(
2079 workInProgress,
packages/react-reconciler/src/ReactFiberCacheComponent.new.js
+8 -18
@@ -198,29 +198,18 @@ export function popRootCachePool(root: FiberRoot, renderLanes: Lanes) {
198 // code organization purposes in case that changes.
199 }
200
201 -export function restoreSpawnedCachePool(
201 +export function pushSpawnedCachePool(
202 offscreenWorkInProgress: Fiber,
203 - prevCachePool: SpawnedCachePool,
204 -): SpawnedCachePool | null {
203 + prevCachePool: SpawnedCachePool | null,
204 +): void {
205 if (!enableCache) {
206 - return (null: any);
206 + return;
207 }
208 - const nextParentCache = isPrimaryRenderer
209 - ? CacheContext._currentValue
210 - : CacheContext._currentValue2;
211 - if (nextParentCache !== prevCachePool.parent) {
212 - // There was a refresh. Don't bother restoring anything since the refresh
213 - // will override it.
214 - return null;
208 +
209 + if (prevCachePool === null) {
210 + push(resumedCache, resumedCache.current, offscreenWorkInProgress);
211 } else {
216 - // No refresh. Resume with the previous cache. New Cache boundaries in the
217 - // subtree use this one instead of requesting a fresh one (see
218 - // peekCacheFromPool).
212 push(resumedCache, prevCachePool.pool, offscreenWorkInProgress);
220 -
221 - // Return the cache pool to signal that we did in fact push it. We will
222 - // assign this to the field on the fiber so we know to pop the context.
223 - return prevCachePool;
213 }
214 }
215
@@ -228,6 +217,7 @@ export function popCachePool(workInProgress: Fiber) {
217 if (!enableCache) {
218 return;
219 }
220 +
221 pop(resumedCache, workInProgress);
222 }
223
packages/react-reconciler/src/ReactFiberCacheComponent.old.js
+8 -18
@@ -198,29 +198,18 @@ export function popRootCachePool(root: FiberRoot, renderLanes: Lanes) {
198 // code organization purposes in case that changes.
199 }
200
201 -export function restoreSpawnedCachePool(
201 +export function pushSpawnedCachePool(
202 offscreenWorkInProgress: Fiber,
203 - prevCachePool: SpawnedCachePool,
204 -): SpawnedCachePool | null {
203 + prevCachePool: SpawnedCachePool | null,
204 +): void {
205 if (!enableCache) {
206 - return (null: any);
206 + return;
207 }
208 - const nextParentCache = isPrimaryRenderer
209 - ? CacheContext._currentValue
210 - : CacheContext._currentValue2;
211 - if (nextParentCache !== prevCachePool.parent) {
212 - // There was a refresh. Don't bother restoring anything since the refresh
213 - // will override it.
214 - return null;
208 +
209 + if (prevCachePool === null) {
210 + push(resumedCache, resumedCache.current, offscreenWorkInProgress);
211 } else {
216 - // No refresh. Resume with the previous cache. New Cache boundaries in the
217 - // subtree use this one instead of requesting a fresh one (see
218 - // peekCacheFromPool).
212 push(resumedCache, prevCachePool.pool, offscreenWorkInProgress);
220 -
221 - // Return the cache pool to signal that we did in fact push it. We will
222 - // assign this to the field on the fiber so we know to pop the context.
223 - return prevCachePool;
213 }
214 }
215
@@ -228,6 +217,7 @@ export function popCachePool(workInProgress: Fiber) {
217 if (!enableCache) {
218 return;
219 }
220 +
221 pop(resumedCache, workInProgress);
222 }
223
packages/react-reconciler/src/ReactFiberCompleteWork.new.js
+10 -11
@@ -28,7 +28,7 @@ import type {
28 } from './ReactFiberSuspenseComponent.new';
29 import type {SuspenseContext} from './ReactFiberSuspenseContext.new';
30 import type {OffscreenState} from './ReactFiberOffscreenComponent';
31 -import type {Cache, SpawnedCachePool} from './ReactFiberCacheComponent.new';
31 +import type {Cache} from './ReactFiberCacheComponent.new';
32 import {
33 enableClientRenderFallbackOnHydrationMismatch,
34 enableSuspenseAvoidThisFallback,
@@ -865,8 +865,8 @@ function completeWork(
865 popRootCachePool(fiberRoot, renderLanes);
866
867 let previousCache: Cache | null = null;
868 - if (workInProgress.alternate !== null) {
869 - previousCache = workInProgress.alternate.memoizedState.cache;
868 + if (current !== null) {
869 + previousCache = current.memoizedState.cache;
870 }
871 const cache: Cache = workInProgress.memoizedState.cache;
872 if (cache !== previousCache) {
@@ -1533,11 +1533,11 @@ function completeWork(
1533 if (enableCache) {
1534 let previousCache: Cache | null = null;
1535 if (
1536 - workInProgress.alternate !== null &&
1537 - workInProgress.alternate.memoizedState !== null &&
1538 - workInProgress.alternate.memoizedState.cachePool !== null
1536 + current !== null &&
1537 + current.memoizedState !== null &&
1538 + current.memoizedState.cachePool !== null
1539 ) {
1540 - previousCache = workInProgress.alternate.memoizedState.cachePool.pool;
1540 + previousCache = current.memoizedState.cachePool.pool;
1541 }
1542 let cache: Cache | null = null;
1543 if (
@@ -1550,8 +1550,7 @@ function completeWork(
1550 // Run passive effects to retain/release the cache.
1551 workInProgress.flags |= Passive;
1552 }
1553 - const spawnedCachePool: SpawnedCachePool | null = (workInProgress.updateQueue: any);
1554 - if (spawnedCachePool !== null) {
1553 + if (current !== null) {
1554 popCachePool(workInProgress);
1555 }
1556 }
@@ -1561,8 +1560,8 @@ function completeWork(
1560 case CacheComponent: {
1561 if (enableCache) {
1562 let previousCache: Cache | null = null;
1564 - if (workInProgress.alternate !== null) {
1565 - previousCache = workInProgress.alternate.memoizedState.cache;
1563 + if (current !== null) {
1564 + previousCache = current.memoizedState.cache;
1565 }
1566 const cache: Cache = workInProgress.memoizedState.cache;
1567 if (cache !== previousCache) {
packages/react-reconciler/src/ReactFiberCompleteWork.old.js
+10 -11
@@ -28,7 +28,7 @@ import type {
28 } from './ReactFiberSuspenseComponent.old';
29 import type {SuspenseContext} from './ReactFiberSuspenseContext.old';
30 import type {OffscreenState} from './ReactFiberOffscreenComponent';
31 -import type {Cache, SpawnedCachePool} from './ReactFiberCacheComponent.old';
31 +import type {Cache} from './ReactFiberCacheComponent.old';
32 import {
33 enableClientRenderFallbackOnHydrationMismatch,
34 enableSuspenseAvoidThisFallback,
@@ -865,8 +865,8 @@ function completeWork(
865 popRootCachePool(fiberRoot, renderLanes);
866
867 let previousCache: Cache | null = null;
868 - if (workInProgress.alternate !== null) {
869 - previousCache = workInProgress.alternate.memoizedState.cache;
868 + if (current !== null) {
869 + previousCache = current.memoizedState.cache;
870 }
871 const cache: Cache = workInProgress.memoizedState.cache;
872 if (cache !== previousCache) {
@@ -1533,11 +1533,11 @@ function completeWork(
1533 if (enableCache) {
1534 let previousCache: Cache | null = null;
1535 if (
1536 - workInProgress.alternate !== null &&
1537 - workInProgress.alternate.memoizedState !== null &&
1538 - workInProgress.alternate.memoizedState.cachePool !== null
1536 + current !== null &&
1537 + current.memoizedState !== null &&
1538 + current.memoizedState.cachePool !== null
1539 ) {
1540 - previousCache = workInProgress.alternate.memoizedState.cachePool.pool;
1540 + previousCache = current.memoizedState.cachePool.pool;
1541 }
1542 let cache: Cache | null = null;
1543 if (
@@ -1550,8 +1550,7 @@ function completeWork(
1550 // Run passive effects to retain/release the cache.
1551 workInProgress.flags |= Passive;
1552 }
1553 - const spawnedCachePool: SpawnedCachePool | null = (workInProgress.updateQueue: any);
1554 - if (spawnedCachePool !== null) {
1553 + if (current !== null) {
1554 popCachePool(workInProgress);
1555 }
1556 }
@@ -1561,8 +1560,8 @@ function completeWork(
1560 case CacheComponent: {
1561 if (enableCache) {
1562 let previousCache: Cache | null = null;
1564 - if (workInProgress.alternate !== null) {
1565 - previousCache = workInProgress.alternate.memoizedState.cache;
1563 + if (current !== null) {
1564 + previousCache = current.memoizedState.cache;
1565 }
1566 const cache: Cache = workInProgress.memoizedState.cache;
1567 if (cache !== previousCache) {
packages/react-reconciler/src/ReactFiberUnwindWork.new.js
+13 -7
@@ -11,7 +11,7 @@ import type {ReactContext} from 'shared/ReactTypes';
11 import type {Fiber, FiberRoot} from './ReactInternalTypes';
12 import type {Lanes} from './ReactFiberLane.new';
13 import type {SuspenseState} from './ReactFiberSuspenseComponent.new';
14 -import type {Cache, SpawnedCachePool} from './ReactFiberCacheComponent.new';
14 +import type {Cache} from './ReactFiberCacheComponent.new';
15
16 import {resetWorkInProgressVersions as resetMutableSourceWorkInProgressVersions} from './ReactMutableSource.new';
17 import {
@@ -52,7 +52,11 @@ import {
52 import {transferActualDuration} from './ReactProfilerTimer.new';
53 import {popTreeContext} from './ReactFiberTreeContext.new';
54
55 -function unwindWork(workInProgress: Fiber, renderLanes: Lanes) {
55 +function unwindWork(
56 + current: Fiber | null,
57 + workInProgress: Fiber,
58 + renderLanes: Lanes,
59 +) {
60 // Note: This intentionally doesn't check if we're hydrating because comparing
61 // to the current tree provider fiber is just as fast and less error-prone.
62 // Ideally we would have a special version of the work loop only
@@ -153,8 +157,7 @@ function unwindWork(workInProgress: Fiber, renderLanes: Lanes) {
157 case LegacyHiddenComponent:
158 popRenderLanes(workInProgress);
159 if (enableCache) {
156 - const spawnedCachePool: SpawnedCachePool | null = (workInProgress.updateQueue: any);
157 - if (spawnedCachePool !== null) {
160 + if (current !== null) {
161 popCachePool(workInProgress);
162 }
163 }
@@ -170,7 +173,11 @@ function unwindWork(workInProgress: Fiber, renderLanes: Lanes) {
173 }
174 }
175
173 -function unwindInterruptedWork(interruptedWork: Fiber, renderLanes: Lanes) {
176 +function unwindInterruptedWork(
177 + current: Fiber | null,
178 + interruptedWork: Fiber,
179 + renderLanes: Lanes,
180 +) {
181 // Note: This intentionally doesn't check if we're hydrating because comparing
182 // to the current tree provider fiber is just as fast and less error-prone.
183 // Ideally we would have a special version of the work loop only
@@ -218,8 +225,7 @@ function unwindInterruptedWork(interruptedWork: Fiber, renderLanes: Lanes) {
225 case LegacyHiddenComponent:
226 popRenderLanes(interruptedWork);
227 if (enableCache) {
221 - const spawnedCachePool: SpawnedCachePool | null = (interruptedWork.updateQueue: any);
222 - if (spawnedCachePool !== null) {
228 + if (current !== null) {
229 popCachePool(interruptedWork);
230 }
231 }
packages/react-reconciler/src/ReactFiberUnwindWork.old.js
+13 -7
@@ -11,7 +11,7 @@ import type {ReactContext} from 'shared/ReactTypes';
11 import type {Fiber, FiberRoot} from './ReactInternalTypes';
12 import type {Lanes} from './ReactFiberLane.old';
13 import type {SuspenseState} from './ReactFiberSuspenseComponent.old';
14 -import type {Cache, SpawnedCachePool} from './ReactFiberCacheComponent.old';
14 +import type {Cache} from './ReactFiberCacheComponent.old';
15
16 import {resetWorkInProgressVersions as resetMutableSourceWorkInProgressVersions} from './ReactMutableSource.old';
17 import {
@@ -52,7 +52,11 @@ import {
52 import {transferActualDuration} from './ReactProfilerTimer.old';
53 import {popTreeContext} from './ReactFiberTreeContext.old';
54
55 -function unwindWork(workInProgress: Fiber, renderLanes: Lanes) {
55 +function unwindWork(
56 + current: Fiber | null,
57 + workInProgress: Fiber,
58 + renderLanes: Lanes,
59 +) {
60 // Note: This intentionally doesn't check if we're hydrating because comparing
61 // to the current tree provider fiber is just as fast and less error-prone.
62 // Ideally we would have a special version of the work loop only
@@ -153,8 +157,7 @@ function unwindWork(workInProgress: Fiber, renderLanes: Lanes) {
157 case LegacyHiddenComponent:
158 popRenderLanes(workInProgress);
159 if (enableCache) {
156 - const spawnedCachePool: SpawnedCachePool | null = (workInProgress.updateQueue: any);
157 - if (spawnedCachePool !== null) {
160 + if (current !== null) {
161 popCachePool(workInProgress);
162 }
163 }
@@ -170,7 +173,11 @@ function unwindWork(workInProgress: Fiber, renderLanes: Lanes) {
173 }
174 }
175
173 -function unwindInterruptedWork(interruptedWork: Fiber, renderLanes: Lanes) {
176 +function unwindInterruptedWork(
177 + current: Fiber | null,
178 + interruptedWork: Fiber,
179 + renderLanes: Lanes,
180 +) {
181 // Note: This intentionally doesn't check if we're hydrating because comparing
182 // to the current tree provider fiber is just as fast and less error-prone.
183 // Ideally we would have a special version of the work loop only
@@ -218,8 +225,7 @@ function unwindInterruptedWork(interruptedWork: Fiber, renderLanes: Lanes) {
225 case LegacyHiddenComponent:
226 popRenderLanes(interruptedWork);
227 if (enableCache) {
221 - const spawnedCachePool: SpawnedCachePool | null = (interruptedWork.updateQueue: any);
222 - if (spawnedCachePool !== null) {
228 + if (current !== null) {
229 popCachePool(interruptedWork);
230 }
231 }
packages/react-reconciler/src/ReactFiberWorkLoop.new.js
+8 -3
@@ -1405,7 +1405,12 @@ function prepareFreshStack(root: FiberRoot, lanes: Lanes) {
1405 if (workInProgress !== null) {
1406 let interruptedWork = workInProgress.return;
1407 while (interruptedWork !== null) {
1408 - unwindInterruptedWork(interruptedWork, workInProgressRootRenderLanes);
1408 + const current = interruptedWork.alternate;
1409 + unwindInterruptedWork(
1410 + current,
1411 + interruptedWork,
1412 + workInProgressRootRenderLanes,
1413 + );
1414 interruptedWork = interruptedWork.return;
1415 }
1416 }
@@ -1829,7 +1834,7 @@ function completeUnitOfWork(unitOfWork: Fiber): void {
1834 // This fiber did not complete because something threw. Pop values off
1835 // the stack without entering the complete phase. If this is a boundary,
1836 // capture values if possible.
1832 - const next = unwindWork(completedWork, subtreeRenderLanes);
1837 + const next = unwindWork(current, completedWork, subtreeRenderLanes);
1838
1839 // Because this fiber did not complete, don't reset its lanes.
1840
@@ -2814,7 +2819,7 @@ if (__DEV__ && replayFailedUnitOfWorkWithInvokeGuardedCallback) {
2819 // same fiber again.
2820
2821 // Unwind the failed stack frame
2817 - unwindInterruptedWork(unitOfWork, workInProgressRootRenderLanes);
2822 + unwindInterruptedWork(current, unitOfWork, workInProgressRootRenderLanes);
2823
2824 // Restore the original properties of the fiber.
2825 assignFiberPropertiesInDEV(unitOfWork, originalWorkInProgressCopy);
packages/react-reconciler/src/ReactFiberWorkLoop.old.js
+8 -3
@@ -1405,7 +1405,12 @@ function prepareFreshStack(root: FiberRoot, lanes: Lanes) {
1405 if (workInProgress !== null) {
1406 let interruptedWork = workInProgress.return;
1407 while (interruptedWork !== null) {
1408 - unwindInterruptedWork(interruptedWork, workInProgressRootRenderLanes);
1408 + const current = interruptedWork.alternate;
1409 + unwindInterruptedWork(
1410 + current,
1411 + interruptedWork,
1412 + workInProgressRootRenderLanes,
1413 + );
1414 interruptedWork = interruptedWork.return;
1415 }
1416 }
@@ -1829,7 +1834,7 @@ function completeUnitOfWork(unitOfWork: Fiber): void {
1834 // This fiber did not complete because something threw. Pop values off
1835 // the stack without entering the complete phase. If this is a boundary,
1836 // capture values if possible.
1832 - const next = unwindWork(completedWork, subtreeRenderLanes);
1837 + const next = unwindWork(current, completedWork, subtreeRenderLanes);
1838
1839 // Because this fiber did not complete, don't reset its lanes.
1840
@@ -2814,7 +2819,7 @@ if (__DEV__ && replayFailedUnitOfWorkWithInvokeGuardedCallback) {
2819 // same fiber again.
2820
2821 // Unwind the failed stack frame
2817 - unwindInterruptedWork(unitOfWork, workInProgressRootRenderLanes);
2822 + unwindInterruptedWork(current, unitOfWork, workInProgressRootRenderLanes);
2823
2824 // Restore the original properties of the fiber.
2825 assignFiberPropertiesInDEV(unitOfWork, originalWorkInProgressCopy);