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