From 40eaa22d9af685c239f9d8d42b454d031791e76d Mon Sep 17 00:00:00 2001 From: Luna Ruan Date: Sat, 19 Feb 2022 10:25:27 -0500 Subject: [PATCH] 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. --- .../src/ReactFiberBeginWork.new.js | 70 ++++++++++--------- .../src/ReactFiberBeginWork.old.js | 70 ++++++++++--------- .../src/ReactFiberCacheComponent.new.js | 28 +++----- .../src/ReactFiberCacheComponent.old.js | 28 +++----- .../src/ReactFiberCompleteWork.new.js | 21 +++--- .../src/ReactFiberCompleteWork.old.js | 21 +++--- .../src/ReactFiberUnwindWork.new.js | 20 ++++-- .../src/ReactFiberUnwindWork.old.js | 20 ++++-- .../src/ReactFiberWorkLoop.new.js | 11 ++- .../src/ReactFiberWorkLoop.old.js | 11 ++- 10 files changed, 152 insertions(+), 148 deletions(-) diff --git a/packages/react-reconciler/src/ReactFiberBeginWork.new.js b/packages/react-reconciler/src/ReactFiberBeginWork.new.js index 102ee33376..9b8de1df80 100644 --- a/packages/react-reconciler/src/ReactFiberBeginWork.new.js +++ b/packages/react-reconciler/src/ReactFiberBeginWork.new.js @@ -234,7 +234,7 @@ import { pushRootCachePool, CacheContext, getSuspendedCachePool, - restoreSpawnedCachePool, + pushSpawnedCachePool, getOffscreenDeferredCachePool, } from './ReactFiberCacheComponent.new'; import {createCapturedValue} from './ReactCapturedValue'; @@ -635,11 +635,6 @@ function updateOffscreenComponent( const prevState: OffscreenState | null = current !== null ? current.memoizedState : null; - // If this is not null, this is a cache pool that was carried over from the - // previous render. We will push this to the cache pool context so that we can - // resume in-flight requests. - let spawnedCachePool: SpawnedCachePool | null = null; - if ( nextProps.mode === 'hidden' || nextProps.mode === 'unstable-defer-without-hiding' @@ -652,8 +647,16 @@ function updateOffscreenComponent( cachePool: null, }; workInProgress.memoizedState = nextState; + if (enableCache) { + // push the cache pool even though we're going to bail out + // because otherwise there'd be a context mismatch + if (current !== null) { + pushSpawnedCachePool(workInProgress, null); + } + } pushRenderLanes(workInProgress, renderLanes); } else if (!includesSomeLane(renderLanes, (OffscreenLane: Lane))) { + let spawnedCachePool: SpawnedCachePool | null = null; // We're hidden, and we're not rendering at Offscreen. We will bail out // and resume this tree later. let nextBaseLanes; @@ -663,9 +666,6 @@ function updateOffscreenComponent( if (enableCache) { // Save the cache pool so we can resume later. spawnedCachePool = getOffscreenDeferredCachePool(); - // We don't need to push to the cache pool because we're about to - // bail out. There won't be a context mismatch because we only pop - // the cache pool if `updateQueue` is non-null. } } else { nextBaseLanes = renderLanes; @@ -681,6 +681,14 @@ function updateOffscreenComponent( }; workInProgress.memoizedState = nextState; workInProgress.updateQueue = null; + if (enableCache) { + // push the cache pool even though we're going to bail out + // because otherwise there'd be a context mismatch + if (current !== null) { + pushSpawnedCachePool(workInProgress, null); + } + } + // We're about to bail out, but we need to push this to the stack anyway // to avoid a push/pop misalignment. pushRenderLanes(workInProgress, nextBaseLanes); @@ -701,19 +709,6 @@ function updateOffscreenComponent( // This is the second render. The surrounding visible content has already // committed. Now we resume rendering the hidden tree. - if (enableCache && prevState !== null) { - // If the render that spawned this one accessed the cache pool, resume - // using the same cache. Unless the parent changed, since that means - // there was a refresh. - const prevCachePool = prevState.cachePool; - if (prevCachePool !== null) { - spawnedCachePool = restoreSpawnedCachePool( - workInProgress, - prevCachePool, - ); - } - } - // Rendering at offscreen, so we can clear the base lanes. const nextState: OffscreenState = { baseLanes: NoLanes, @@ -723,6 +718,14 @@ function updateOffscreenComponent( // Push the lanes that were skipped when we bailed out. const subtreeRenderLanes = prevState !== null ? prevState.baseLanes : renderLanes; + if (enableCache && current !== null) { + // If the render that spawned this one accessed the cache pool, resume + // using the same cache. Unless the parent changed, since that means + // there was a refresh. + const prevCachePool = prevState !== null ? prevState.cachePool : null; + pushSpawnedCachePool(workInProgress, prevCachePool); + } + pushRenderLanes(workInProgress, subtreeRenderLanes); } } else { @@ -738,12 +741,7 @@ function updateOffscreenComponent( // using the same cache. Unless the parent changed, since that means // there was a refresh. const prevCachePool = prevState.cachePool; - if (prevCachePool !== null) { - spawnedCachePool = restoreSpawnedCachePool( - workInProgress, - prevCachePool, - ); - } + pushSpawnedCachePool(workInProgress, prevCachePool); } // Since we're not hidden anymore, reset the state @@ -753,16 +751,19 @@ function updateOffscreenComponent( // special to do. Need to push to the stack regardless, though, to avoid // a push/pop misalignment. subtreeRenderLanes = renderLanes; + + if (enableCache) { + // If the render that spawned this one accessed the cache pool, resume + // using the same cache. Unless the parent changed, since that means + // there was a refresh. + if (current !== null) { + pushSpawnedCachePool(workInProgress, null); + } + } } pushRenderLanes(workInProgress, subtreeRenderLanes); } - if (enableCache) { - // If we have a cache pool from a previous render attempt, then this will be - // non-null. We use this to infer whether to push/pop the cache context. - workInProgress.updateQueue = spawnedCachePool; - } - if (enablePersistentOffscreenHostContainer && supportsPersistence) { // In persistent mode, the offscreen children are wrapped in a host node. // TODO: Optimize this to use the OffscreenComponent fiber instead of @@ -2072,6 +2073,7 @@ function updateSuspenseComponent(current, workInProgress, renderLanes) { const nextPrimaryChildren = nextProps.children; const nextFallbackChildren = nextProps.fallback; + if (showFallback) { const fallbackFragment = mountSuspenseFallbackChildren( workInProgress, diff --git a/packages/react-reconciler/src/ReactFiberBeginWork.old.js b/packages/react-reconciler/src/ReactFiberBeginWork.old.js index 5876cb3eee..457088598e 100644 --- a/packages/react-reconciler/src/ReactFiberBeginWork.old.js +++ b/packages/react-reconciler/src/ReactFiberBeginWork.old.js @@ -234,7 +234,7 @@ import { pushRootCachePool, CacheContext, getSuspendedCachePool, - restoreSpawnedCachePool, + pushSpawnedCachePool, getOffscreenDeferredCachePool, } from './ReactFiberCacheComponent.old'; import {createCapturedValue} from './ReactCapturedValue'; @@ -635,11 +635,6 @@ function updateOffscreenComponent( const prevState: OffscreenState | null = current !== null ? current.memoizedState : null; - // If this is not null, this is a cache pool that was carried over from the - // previous render. We will push this to the cache pool context so that we can - // resume in-flight requests. - let spawnedCachePool: SpawnedCachePool | null = null; - if ( nextProps.mode === 'hidden' || nextProps.mode === 'unstable-defer-without-hiding' @@ -652,8 +647,16 @@ function updateOffscreenComponent( cachePool: null, }; workInProgress.memoizedState = nextState; + if (enableCache) { + // push the cache pool even though we're going to bail out + // because otherwise there'd be a context mismatch + if (current !== null) { + pushSpawnedCachePool(workInProgress, null); + } + } pushRenderLanes(workInProgress, renderLanes); } else if (!includesSomeLane(renderLanes, (OffscreenLane: Lane))) { + let spawnedCachePool: SpawnedCachePool | null = null; // We're hidden, and we're not rendering at Offscreen. We will bail out // and resume this tree later. let nextBaseLanes; @@ -663,9 +666,6 @@ function updateOffscreenComponent( if (enableCache) { // Save the cache pool so we can resume later. spawnedCachePool = getOffscreenDeferredCachePool(); - // We don't need to push to the cache pool because we're about to - // bail out. There won't be a context mismatch because we only pop - // the cache pool if `updateQueue` is non-null. } } else { nextBaseLanes = renderLanes; @@ -681,6 +681,14 @@ function updateOffscreenComponent( }; workInProgress.memoizedState = nextState; workInProgress.updateQueue = null; + if (enableCache) { + // push the cache pool even though we're going to bail out + // because otherwise there'd be a context mismatch + if (current !== null) { + pushSpawnedCachePool(workInProgress, null); + } + } + // We're about to bail out, but we need to push this to the stack anyway // to avoid a push/pop misalignment. pushRenderLanes(workInProgress, nextBaseLanes); @@ -701,19 +709,6 @@ function updateOffscreenComponent( // This is the second render. The surrounding visible content has already // committed. Now we resume rendering the hidden tree. - if (enableCache && prevState !== null) { - // If the render that spawned this one accessed the cache pool, resume - // using the same cache. Unless the parent changed, since that means - // there was a refresh. - const prevCachePool = prevState.cachePool; - if (prevCachePool !== null) { - spawnedCachePool = restoreSpawnedCachePool( - workInProgress, - prevCachePool, - ); - } - } - // Rendering at offscreen, so we can clear the base lanes. const nextState: OffscreenState = { baseLanes: NoLanes, @@ -723,6 +718,14 @@ function updateOffscreenComponent( // Push the lanes that were skipped when we bailed out. const subtreeRenderLanes = prevState !== null ? prevState.baseLanes : renderLanes; + if (enableCache && current !== null) { + // If the render that spawned this one accessed the cache pool, resume + // using the same cache. Unless the parent changed, since that means + // there was a refresh. + const prevCachePool = prevState !== null ? prevState.cachePool : null; + pushSpawnedCachePool(workInProgress, prevCachePool); + } + pushRenderLanes(workInProgress, subtreeRenderLanes); } } else { @@ -738,12 +741,7 @@ function updateOffscreenComponent( // using the same cache. Unless the parent changed, since that means // there was a refresh. const prevCachePool = prevState.cachePool; - if (prevCachePool !== null) { - spawnedCachePool = restoreSpawnedCachePool( - workInProgress, - prevCachePool, - ); - } + pushSpawnedCachePool(workInProgress, prevCachePool); } // Since we're not hidden anymore, reset the state @@ -753,16 +751,19 @@ function updateOffscreenComponent( // special to do. Need to push to the stack regardless, though, to avoid // a push/pop misalignment. subtreeRenderLanes = renderLanes; + + if (enableCache) { + // If the render that spawned this one accessed the cache pool, resume + // using the same cache. Unless the parent changed, since that means + // there was a refresh. + if (current !== null) { + pushSpawnedCachePool(workInProgress, null); + } + } } pushRenderLanes(workInProgress, subtreeRenderLanes); } - if (enableCache) { - // If we have a cache pool from a previous render attempt, then this will be - // non-null. We use this to infer whether to push/pop the cache context. - workInProgress.updateQueue = spawnedCachePool; - } - if (enablePersistentOffscreenHostContainer && supportsPersistence) { // In persistent mode, the offscreen children are wrapped in a host node. // TODO: Optimize this to use the OffscreenComponent fiber instead of @@ -2072,6 +2073,7 @@ function updateSuspenseComponent(current, workInProgress, renderLanes) { const nextPrimaryChildren = nextProps.children; const nextFallbackChildren = nextProps.fallback; + if (showFallback) { const fallbackFragment = mountSuspenseFallbackChildren( workInProgress, diff --git a/packages/react-reconciler/src/ReactFiberCacheComponent.new.js b/packages/react-reconciler/src/ReactFiberCacheComponent.new.js index cf851af6e3..3d1db8124b 100644 --- a/packages/react-reconciler/src/ReactFiberCacheComponent.new.js +++ b/packages/react-reconciler/src/ReactFiberCacheComponent.new.js @@ -198,29 +198,18 @@ export function popRootCachePool(root: FiberRoot, renderLanes: Lanes) { // code organization purposes in case that changes. } -export function restoreSpawnedCachePool( +export function pushSpawnedCachePool( offscreenWorkInProgress: Fiber, - prevCachePool: SpawnedCachePool, -): SpawnedCachePool | null { + prevCachePool: SpawnedCachePool | null, +): void { if (!enableCache) { - return (null: any); + return; } - const nextParentCache = isPrimaryRenderer - ? CacheContext._currentValue - : CacheContext._currentValue2; - if (nextParentCache !== prevCachePool.parent) { - // There was a refresh. Don't bother restoring anything since the refresh - // will override it. - return null; - } else { - // No refresh. Resume with the previous cache. New Cache boundaries in the - // subtree use this one instead of requesting a fresh one (see - // peekCacheFromPool). - push(resumedCache, prevCachePool.pool, offscreenWorkInProgress); - // Return the cache pool to signal that we did in fact push it. We will - // assign this to the field on the fiber so we know to pop the context. - return prevCachePool; + if (prevCachePool === null) { + push(resumedCache, resumedCache.current, offscreenWorkInProgress); + } else { + push(resumedCache, prevCachePool.pool, offscreenWorkInProgress); } } @@ -228,6 +217,7 @@ export function popCachePool(workInProgress: Fiber) { if (!enableCache) { return; } + pop(resumedCache, workInProgress); } diff --git a/packages/react-reconciler/src/ReactFiberCacheComponent.old.js b/packages/react-reconciler/src/ReactFiberCacheComponent.old.js index 692dba7813..74dc9a449a 100644 --- a/packages/react-reconciler/src/ReactFiberCacheComponent.old.js +++ b/packages/react-reconciler/src/ReactFiberCacheComponent.old.js @@ -198,29 +198,18 @@ export function popRootCachePool(root: FiberRoot, renderLanes: Lanes) { // code organization purposes in case that changes. } -export function restoreSpawnedCachePool( +export function pushSpawnedCachePool( offscreenWorkInProgress: Fiber, - prevCachePool: SpawnedCachePool, -): SpawnedCachePool | null { + prevCachePool: SpawnedCachePool | null, +): void { if (!enableCache) { - return (null: any); + return; } - const nextParentCache = isPrimaryRenderer - ? CacheContext._currentValue - : CacheContext._currentValue2; - if (nextParentCache !== prevCachePool.parent) { - // There was a refresh. Don't bother restoring anything since the refresh - // will override it. - return null; - } else { - // No refresh. Resume with the previous cache. New Cache boundaries in the - // subtree use this one instead of requesting a fresh one (see - // peekCacheFromPool). - push(resumedCache, prevCachePool.pool, offscreenWorkInProgress); - // Return the cache pool to signal that we did in fact push it. We will - // assign this to the field on the fiber so we know to pop the context. - return prevCachePool; + if (prevCachePool === null) { + push(resumedCache, resumedCache.current, offscreenWorkInProgress); + } else { + push(resumedCache, prevCachePool.pool, offscreenWorkInProgress); } } @@ -228,6 +217,7 @@ export function popCachePool(workInProgress: Fiber) { if (!enableCache) { return; } + pop(resumedCache, workInProgress); } diff --git a/packages/react-reconciler/src/ReactFiberCompleteWork.new.js b/packages/react-reconciler/src/ReactFiberCompleteWork.new.js index 39f724c76d..bb01e2b8a2 100644 --- a/packages/react-reconciler/src/ReactFiberCompleteWork.new.js +++ b/packages/react-reconciler/src/ReactFiberCompleteWork.new.js @@ -28,7 +28,7 @@ import type { } from './ReactFiberSuspenseComponent.new'; import type {SuspenseContext} from './ReactFiberSuspenseContext.new'; import type {OffscreenState} from './ReactFiberOffscreenComponent'; -import type {Cache, SpawnedCachePool} from './ReactFiberCacheComponent.new'; +import type {Cache} from './ReactFiberCacheComponent.new'; import { enableClientRenderFallbackOnHydrationMismatch, enableSuspenseAvoidThisFallback, @@ -865,8 +865,8 @@ function completeWork( popRootCachePool(fiberRoot, renderLanes); let previousCache: Cache | null = null; - if (workInProgress.alternate !== null) { - previousCache = workInProgress.alternate.memoizedState.cache; + if (current !== null) { + previousCache = current.memoizedState.cache; } const cache: Cache = workInProgress.memoizedState.cache; if (cache !== previousCache) { @@ -1533,11 +1533,11 @@ function completeWork( if (enableCache) { let previousCache: Cache | null = null; if ( - workInProgress.alternate !== null && - workInProgress.alternate.memoizedState !== null && - workInProgress.alternate.memoizedState.cachePool !== null + current !== null && + current.memoizedState !== null && + current.memoizedState.cachePool !== null ) { - previousCache = workInProgress.alternate.memoizedState.cachePool.pool; + previousCache = current.memoizedState.cachePool.pool; } let cache: Cache | null = null; if ( @@ -1550,8 +1550,7 @@ function completeWork( // Run passive effects to retain/release the cache. workInProgress.flags |= Passive; } - const spawnedCachePool: SpawnedCachePool | null = (workInProgress.updateQueue: any); - if (spawnedCachePool !== null) { + if (current !== null) { popCachePool(workInProgress); } } @@ -1561,8 +1560,8 @@ function completeWork( case CacheComponent: { if (enableCache) { let previousCache: Cache | null = null; - if (workInProgress.alternate !== null) { - previousCache = workInProgress.alternate.memoizedState.cache; + if (current !== null) { + previousCache = current.memoizedState.cache; } const cache: Cache = workInProgress.memoizedState.cache; if (cache !== previousCache) { diff --git a/packages/react-reconciler/src/ReactFiberCompleteWork.old.js b/packages/react-reconciler/src/ReactFiberCompleteWork.old.js index c7baf36d16..0d9de679a0 100644 --- a/packages/react-reconciler/src/ReactFiberCompleteWork.old.js +++ b/packages/react-reconciler/src/ReactFiberCompleteWork.old.js @@ -28,7 +28,7 @@ import type { } from './ReactFiberSuspenseComponent.old'; import type {SuspenseContext} from './ReactFiberSuspenseContext.old'; import type {OffscreenState} from './ReactFiberOffscreenComponent'; -import type {Cache, SpawnedCachePool} from './ReactFiberCacheComponent.old'; +import type {Cache} from './ReactFiberCacheComponent.old'; import { enableClientRenderFallbackOnHydrationMismatch, enableSuspenseAvoidThisFallback, @@ -865,8 +865,8 @@ function completeWork( popRootCachePool(fiberRoot, renderLanes); let previousCache: Cache | null = null; - if (workInProgress.alternate !== null) { - previousCache = workInProgress.alternate.memoizedState.cache; + if (current !== null) { + previousCache = current.memoizedState.cache; } const cache: Cache = workInProgress.memoizedState.cache; if (cache !== previousCache) { @@ -1533,11 +1533,11 @@ function completeWork( if (enableCache) { let previousCache: Cache | null = null; if ( - workInProgress.alternate !== null && - workInProgress.alternate.memoizedState !== null && - workInProgress.alternate.memoizedState.cachePool !== null + current !== null && + current.memoizedState !== null && + current.memoizedState.cachePool !== null ) { - previousCache = workInProgress.alternate.memoizedState.cachePool.pool; + previousCache = current.memoizedState.cachePool.pool; } let cache: Cache | null = null; if ( @@ -1550,8 +1550,7 @@ function completeWork( // Run passive effects to retain/release the cache. workInProgress.flags |= Passive; } - const spawnedCachePool: SpawnedCachePool | null = (workInProgress.updateQueue: any); - if (spawnedCachePool !== null) { + if (current !== null) { popCachePool(workInProgress); } } @@ -1561,8 +1560,8 @@ function completeWork( case CacheComponent: { if (enableCache) { let previousCache: Cache | null = null; - if (workInProgress.alternate !== null) { - previousCache = workInProgress.alternate.memoizedState.cache; + if (current !== null) { + previousCache = current.memoizedState.cache; } const cache: Cache = workInProgress.memoizedState.cache; if (cache !== previousCache) { diff --git a/packages/react-reconciler/src/ReactFiberUnwindWork.new.js b/packages/react-reconciler/src/ReactFiberUnwindWork.new.js index a43c021d98..aa1b391b03 100644 --- a/packages/react-reconciler/src/ReactFiberUnwindWork.new.js +++ b/packages/react-reconciler/src/ReactFiberUnwindWork.new.js @@ -11,7 +11,7 @@ import type {ReactContext} from 'shared/ReactTypes'; import type {Fiber, FiberRoot} from './ReactInternalTypes'; import type {Lanes} from './ReactFiberLane.new'; import type {SuspenseState} from './ReactFiberSuspenseComponent.new'; -import type {Cache, SpawnedCachePool} from './ReactFiberCacheComponent.new'; +import type {Cache} from './ReactFiberCacheComponent.new'; import {resetWorkInProgressVersions as resetMutableSourceWorkInProgressVersions} from './ReactMutableSource.new'; import { @@ -52,7 +52,11 @@ import { import {transferActualDuration} from './ReactProfilerTimer.new'; import {popTreeContext} from './ReactFiberTreeContext.new'; -function unwindWork(workInProgress: Fiber, renderLanes: Lanes) { +function unwindWork( + current: Fiber | null, + workInProgress: Fiber, + renderLanes: Lanes, +) { // Note: This intentionally doesn't check if we're hydrating because comparing // to the current tree provider fiber is just as fast and less error-prone. // Ideally we would have a special version of the work loop only @@ -153,8 +157,7 @@ function unwindWork(workInProgress: Fiber, renderLanes: Lanes) { case LegacyHiddenComponent: popRenderLanes(workInProgress); if (enableCache) { - const spawnedCachePool: SpawnedCachePool | null = (workInProgress.updateQueue: any); - if (spawnedCachePool !== null) { + if (current !== null) { popCachePool(workInProgress); } } @@ -170,7 +173,11 @@ function unwindWork(workInProgress: Fiber, renderLanes: Lanes) { } } -function unwindInterruptedWork(interruptedWork: Fiber, renderLanes: Lanes) { +function unwindInterruptedWork( + current: Fiber | null, + interruptedWork: Fiber, + renderLanes: Lanes, +) { // Note: This intentionally doesn't check if we're hydrating because comparing // to the current tree provider fiber is just as fast and less error-prone. // Ideally we would have a special version of the work loop only @@ -218,8 +225,7 @@ function unwindInterruptedWork(interruptedWork: Fiber, renderLanes: Lanes) { case LegacyHiddenComponent: popRenderLanes(interruptedWork); if (enableCache) { - const spawnedCachePool: SpawnedCachePool | null = (interruptedWork.updateQueue: any); - if (spawnedCachePool !== null) { + if (current !== null) { popCachePool(interruptedWork); } } diff --git a/packages/react-reconciler/src/ReactFiberUnwindWork.old.js b/packages/react-reconciler/src/ReactFiberUnwindWork.old.js index e0cf7cc2f0..cb5df61782 100644 --- a/packages/react-reconciler/src/ReactFiberUnwindWork.old.js +++ b/packages/react-reconciler/src/ReactFiberUnwindWork.old.js @@ -11,7 +11,7 @@ import type {ReactContext} from 'shared/ReactTypes'; import type {Fiber, FiberRoot} from './ReactInternalTypes'; import type {Lanes} from './ReactFiberLane.old'; import type {SuspenseState} from './ReactFiberSuspenseComponent.old'; -import type {Cache, SpawnedCachePool} from './ReactFiberCacheComponent.old'; +import type {Cache} from './ReactFiberCacheComponent.old'; import {resetWorkInProgressVersions as resetMutableSourceWorkInProgressVersions} from './ReactMutableSource.old'; import { @@ -52,7 +52,11 @@ import { import {transferActualDuration} from './ReactProfilerTimer.old'; import {popTreeContext} from './ReactFiberTreeContext.old'; -function unwindWork(workInProgress: Fiber, renderLanes: Lanes) { +function unwindWork( + current: Fiber | null, + workInProgress: Fiber, + renderLanes: Lanes, +) { // Note: This intentionally doesn't check if we're hydrating because comparing // to the current tree provider fiber is just as fast and less error-prone. // Ideally we would have a special version of the work loop only @@ -153,8 +157,7 @@ function unwindWork(workInProgress: Fiber, renderLanes: Lanes) { case LegacyHiddenComponent: popRenderLanes(workInProgress); if (enableCache) { - const spawnedCachePool: SpawnedCachePool | null = (workInProgress.updateQueue: any); - if (spawnedCachePool !== null) { + if (current !== null) { popCachePool(workInProgress); } } @@ -170,7 +173,11 @@ function unwindWork(workInProgress: Fiber, renderLanes: Lanes) { } } -function unwindInterruptedWork(interruptedWork: Fiber, renderLanes: Lanes) { +function unwindInterruptedWork( + current: Fiber | null, + interruptedWork: Fiber, + renderLanes: Lanes, +) { // Note: This intentionally doesn't check if we're hydrating because comparing // to the current tree provider fiber is just as fast and less error-prone. // Ideally we would have a special version of the work loop only @@ -218,8 +225,7 @@ function unwindInterruptedWork(interruptedWork: Fiber, renderLanes: Lanes) { case LegacyHiddenComponent: popRenderLanes(interruptedWork); if (enableCache) { - const spawnedCachePool: SpawnedCachePool | null = (interruptedWork.updateQueue: any); - if (spawnedCachePool !== null) { + if (current !== null) { popCachePool(interruptedWork); } } diff --git a/packages/react-reconciler/src/ReactFiberWorkLoop.new.js b/packages/react-reconciler/src/ReactFiberWorkLoop.new.js index c69455bde3..cf0fb63f19 100644 --- a/packages/react-reconciler/src/ReactFiberWorkLoop.new.js +++ b/packages/react-reconciler/src/ReactFiberWorkLoop.new.js @@ -1405,7 +1405,12 @@ function prepareFreshStack(root: FiberRoot, lanes: Lanes) { if (workInProgress !== null) { let interruptedWork = workInProgress.return; while (interruptedWork !== null) { - unwindInterruptedWork(interruptedWork, workInProgressRootRenderLanes); + const current = interruptedWork.alternate; + unwindInterruptedWork( + current, + interruptedWork, + workInProgressRootRenderLanes, + ); interruptedWork = interruptedWork.return; } } @@ -1829,7 +1834,7 @@ function completeUnitOfWork(unitOfWork: Fiber): void { // This fiber did not complete because something threw. Pop values off // the stack without entering the complete phase. If this is a boundary, // capture values if possible. - const next = unwindWork(completedWork, subtreeRenderLanes); + const next = unwindWork(current, completedWork, subtreeRenderLanes); // Because this fiber did not complete, don't reset its lanes. @@ -2814,7 +2819,7 @@ if (__DEV__ && replayFailedUnitOfWorkWithInvokeGuardedCallback) { // same fiber again. // Unwind the failed stack frame - unwindInterruptedWork(unitOfWork, workInProgressRootRenderLanes); + unwindInterruptedWork(current, unitOfWork, workInProgressRootRenderLanes); // Restore the original properties of the fiber. assignFiberPropertiesInDEV(unitOfWork, originalWorkInProgressCopy); diff --git a/packages/react-reconciler/src/ReactFiberWorkLoop.old.js b/packages/react-reconciler/src/ReactFiberWorkLoop.old.js index ec9e54c1ca..b823ed9133 100644 --- a/packages/react-reconciler/src/ReactFiberWorkLoop.old.js +++ b/packages/react-reconciler/src/ReactFiberWorkLoop.old.js @@ -1405,7 +1405,12 @@ function prepareFreshStack(root: FiberRoot, lanes: Lanes) { if (workInProgress !== null) { let interruptedWork = workInProgress.return; while (interruptedWork !== null) { - unwindInterruptedWork(interruptedWork, workInProgressRootRenderLanes); + const current = interruptedWork.alternate; + unwindInterruptedWork( + current, + interruptedWork, + workInProgressRootRenderLanes, + ); interruptedWork = interruptedWork.return; } } @@ -1829,7 +1834,7 @@ function completeUnitOfWork(unitOfWork: Fiber): void { // This fiber did not complete because something threw. Pop values off // the stack without entering the complete phase. If this is a boundary, // capture values if possible. - const next = unwindWork(completedWork, subtreeRenderLanes); + const next = unwindWork(current, completedWork, subtreeRenderLanes); // Because this fiber did not complete, don't reset its lanes. @@ -2814,7 +2819,7 @@ if (__DEV__ && replayFailedUnitOfWorkWithInvokeGuardedCallback) { // same fiber again. // Unwind the failed stack frame - unwindInterruptedWork(unitOfWork, workInProgressRootRenderLanes); + unwindInterruptedWork(current, unitOfWork, workInProgressRootRenderLanes); // Restore the original properties of the fiber. assignFiberPropertiesInDEV(unitOfWork, originalWorkInProgressCopy);