Skip to content

[draft] Move resetChildLanes into complete work #19801

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

Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions packages/react-reconciler/src/ReactFiber.new.js
Original file line number Diff line number Diff line change
@@ -283,7 +283,6 @@ export function createWorkInProgress(current: Fiber, pendingProps: any): Fiber {
workInProgress.type = current.type;

// We already have an alternate.
workInProgress.subtreeFlags = NoFlags;
workInProgress.deletions = null;

if (enableProfilerTimer) {
@@ -299,7 +298,8 @@ export function createWorkInProgress(current: Fiber, pendingProps: any): Fiber {
// Reset all effects except static ones.
// Static effects are not specific to a render.
workInProgress.flags = current.flags & StaticMask;
workInProgress.childLanes = current.childLanes;
workInProgress.subtreeFlags = current.subtreeFlags & StaticMask;
workInProgress.childLanes = NoLanes;
workInProgress.lanes = current.lanes;

workInProgress.child = current.child;
@@ -388,7 +388,7 @@ export function resetWorkInProgress(workInProgress: Fiber, renderLanes: Lanes) {
}
} else {
// Reset to the cloned values that createWorkInProgress would've.
workInProgress.childLanes = current.childLanes;
workInProgress.childLanes = NoLanes;
workInProgress.lanes = current.lanes;

workInProgress.child = current.child;
32 changes: 27 additions & 5 deletions packages/react-reconciler/src/ReactFiberBeginWork.new.js
Original file line number Diff line number Diff line change
@@ -1883,7 +1883,7 @@ function updateSuspenseComponent(current, workInProgress, renderLanes) {
prevOffscreenState === null
? mountSuspenseOffscreenState(renderLanes)
: updateSuspenseOffscreenState(prevOffscreenState, renderLanes);
primaryChildFragment.childLanes = getRemainingWorkInPrimaryTree(
primaryChildFragment.childLanes = workInProgress.childLanes = getRemainingWorkInPrimaryTree(
current,
renderLanes,
);
@@ -1920,7 +1920,8 @@ function updateSuspenseComponent(current, workInProgress, renderLanes) {
prevOffscreenState === null
? mountSuspenseOffscreenState(renderLanes)
: updateSuspenseOffscreenState(prevOffscreenState, renderLanes);
primaryChildFragment.childLanes = getRemainingWorkInPrimaryTree(
// TODO (effects) Document
primaryChildFragment.childLanes = workInProgress.childLanes = getRemainingWorkInPrimaryTree(
current,
renderLanes,
);
@@ -1989,6 +1990,18 @@ function mountSuspenseFallbackChildren(
primaryChildFragment.childLanes = NoLanes;
primaryChildFragment.pendingProps = primaryChildProps;

// TODO (effects) This is tricky because by the time we are resetting the childLanes here
// they have already bubbled to the parent SuspenseComponent and its parent also
// (during the previous complete phase bubbling back up to Suspense).
//
// Compare this to the old fork, where we will restart work on the Suspense node
// before bubbling higher (and letting the values leak out).
//
// We could reset childLanes for the parent SuspenseComponent safely,
// but we can't reset childLanes for its parent without potentially erasing sibling updates.
// Instead we need to prevent the childLanes from bubbling in the first place during a suspend.
workInProgress.childLanes = NoLanes;

if (enableProfilerTimer && workInProgress.mode & ProfileMode) {
// Reset the durations from the first pass so they aren't included in the
// final amounts. This seems counterintuitive, since we're intentionally
@@ -2110,6 +2123,9 @@ function updateSuspenseFallbackChildren(
primaryChildFragment.childLanes = NoLanes;
primaryChildFragment.pendingProps = primaryChildProps;

// TODO (effects)
workInProgress.childLanes = NoLanes;

if (enableProfilerTimer && workInProgress.mode & ProfileMode) {
// Reset the durations from the first pass so they aren't included in the
// final amounts. This seems counterintuitive, since we're intentionally
@@ -2969,7 +2985,7 @@ function bailoutOnAlreadyFinishedWork(
markSkippedUpdateLanes(workInProgress.lanes);

// Check if the children have any pending work.
if (!includesSomeLane(renderLanes, workInProgress.childLanes)) {
if (!includesSomeLane(renderLanes, current.childLanes)) {
// The children don't have any work either. We can skip them.
// TODO: Once we add back resuming, we should check if the children are
// a work-in-progress set. If so, we need to transfer their effects.
@@ -3118,7 +3134,7 @@ function beginWork(
// Profiler should only call onRender when one of its descendants actually rendered.
const hasChildWork = includesSomeLane(
renderLanes,
workInProgress.childLanes,
current.childLanes,
);
if (hasChildWork) {
workInProgress.flags |= Update;
@@ -3197,9 +3213,15 @@ function beginWork(
case SuspenseListComponent: {
const didSuspendBefore = (current.flags & DidCapture) !== NoFlags;

// TODO current.childLanes is right; workInProgress.childLanes is wrong.
// Presumably we bubbled something up that we shouldn't have then.
// Maybet his is a variation of the Suspense thing earlier?
// Either we need to reset (or not copy)?
// Or maybe we need to *set* or update in this case?
const hasChildWork = includesSomeLane(
renderLanes,
workInProgress.childLanes,
// workInProgress.childLanes,
current.childLanes, // This causes a loop for some tests
);

if (didSuspendBefore) {
Loading