Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove dependency on Offscreen Fiber updateQueue for React Cache #23229

Merged
merged 2 commits into from Feb 19, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
70 changes: 36 additions & 34 deletions packages/react-reconciler/src/ReactFiberBeginWork.new.js
Expand Up @@ -236,7 +236,7 @@ import {
pushRootCachePool,
CacheContext,
getSuspendedCachePool,
restoreSpawnedCachePool,
pushSpawnedCachePool,
getOffscreenDeferredCachePool,
} from './ReactFiberCacheComponent.new';
import {createCapturedValue} from './ReactCapturedValue';
Expand Down Expand Up @@ -637,11 +637,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'
Expand All @@ -654,8 +649,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;
Expand All @@ -665,9 +668,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;
Expand All @@ -683,6 +683,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);
Expand All @@ -703,19 +711,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,
Expand All @@ -725,6 +720,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 {
Expand All @@ -740,12 +743,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
Expand All @@ -755,16 +753,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
Expand Down Expand Up @@ -2074,6 +2075,7 @@ function updateSuspenseComponent(current, workInProgress, renderLanes) {

const nextPrimaryChildren = nextProps.children;
const nextFallbackChildren = nextProps.fallback;

if (showFallback) {
const fallbackFragment = mountSuspenseFallbackChildren(
workInProgress,
Expand Down
70 changes: 36 additions & 34 deletions packages/react-reconciler/src/ReactFiberBeginWork.old.js
Expand Up @@ -236,7 +236,7 @@ import {
pushRootCachePool,
CacheContext,
getSuspendedCachePool,
restoreSpawnedCachePool,
pushSpawnedCachePool,
getOffscreenDeferredCachePool,
} from './ReactFiberCacheComponent.old';
import {createCapturedValue} from './ReactCapturedValue';
Expand Down Expand Up @@ -637,11 +637,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'
Expand All @@ -654,8 +649,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;
Expand All @@ -665,9 +668,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;
Expand All @@ -683,6 +683,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);
Expand All @@ -703,19 +711,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,
Expand All @@ -725,6 +720,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 {
Expand All @@ -740,12 +743,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
Expand All @@ -755,16 +753,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
Expand Down Expand Up @@ -2074,6 +2075,7 @@ function updateSuspenseComponent(current, workInProgress, renderLanes) {

const nextPrimaryChildren = nextProps.children;
const nextFallbackChildren = nextProps.fallback;

if (showFallback) {
const fallbackFragment = mountSuspenseFallbackChildren(
workInProgress,
Expand Down
26 changes: 8 additions & 18 deletions packages/react-reconciler/src/ReactFiberCacheComponent.new.js
Expand Up @@ -198,36 +198,26 @@ 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;

if (prevCachePool === null) {
push(resumedCache, resumedCache.current, offscreenWorkInProgress);
} 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;
}
}

export function popCachePool(workInProgress: Fiber) {
if (!enableCache) {
return;
}

pop(resumedCache, workInProgress);
}

Expand Down
26 changes: 8 additions & 18 deletions packages/react-reconciler/src/ReactFiberCacheComponent.old.js
Expand Up @@ -198,36 +198,26 @@ 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;

if (prevCachePool === null) {
push(resumedCache, resumedCache.current, offscreenWorkInProgress);
} 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;
}
}

export function popCachePool(workInProgress: Fiber) {
if (!enableCache) {
return;
}

pop(resumedCache, workInProgress);
}

Expand Down