Skip to content

Commit 6ecd2cc

Browse files
committed
Implement fix via bailoutOffscreenComponent
1 parent 9e25af3 commit 6ecd2cc

File tree

2 files changed

+44
-39
lines changed

2 files changed

+44
-39
lines changed

packages/react-reconciler/src/ReactFiberBeginWork.js

Lines changed: 44 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -278,10 +278,7 @@ import {
278278
createCapturedValueFromError,
279279
createCapturedValueAtFiber,
280280
} from './ReactCapturedValue';
281-
import {
282-
OffscreenHidden,
283-
OffscreenVisible,
284-
} from './ReactFiberOffscreenComponent';
281+
import {OffscreenVisible} from './ReactFiberOffscreenComponent';
285282
import {
286283
createClassErrorUpdate,
287284
initializeClassErrorUpdate,
@@ -622,21 +619,22 @@ function updateOffscreenComponent(
622619
const prevState: OffscreenState | null =
623620
current !== null ? current.memoizedState : null;
624621

625-
const nextHidden =
626-
nextProps.mode === 'hidden' ||
627-
(enableLegacyHidden && nextProps.mode === 'unstable-defer-without-hiding');
628-
629622
if (current === null && workInProgress.stateNode === null) {
630-
const primaryChildInstance = {
631-
_visibility: nextHidden ? OffscreenHidden : OffscreenVisible,
623+
// We previously reset the work-in-progress.
624+
// We need to create a new Offscreen instance.
625+
const primaryChildInstance: OffscreenInstance = {
626+
_visibility: OffscreenVisible,
632627
_pendingMarkers: null,
633628
_retryCache: null,
634629
_transitions: null,
635630
};
636631
workInProgress.stateNode = primaryChildInstance;
637632
}
638633

639-
if (nextHidden) {
634+
if (
635+
nextProps.mode === 'hidden' ||
636+
(enableLegacyHidden && nextProps.mode === 'unstable-defer-without-hiding')
637+
) {
640638
// Rendering a hidden tree.
641639

642640
const didSuspend = (workInProgress.flags & DidCapture) !== NoFlags;
@@ -801,6 +799,26 @@ function updateOffscreenComponent(
801799
return workInProgress.child;
802800
}
803801

802+
function bailoutOffscreenComponent(
803+
current: Fiber | null,
804+
workInProgress: Fiber,
805+
): Fiber | null {
806+
if (
807+
(current === null || current.tag !== OffscreenComponent) &&
808+
workInProgress.stateNode === null
809+
) {
810+
const primaryChildInstance: OffscreenInstance = {
811+
_visibility: OffscreenVisible,
812+
_pendingMarkers: null,
813+
_retryCache: null,
814+
_transitions: null,
815+
};
816+
workInProgress.stateNode = primaryChildInstance;
817+
}
818+
819+
return workInProgress.sibling;
820+
}
821+
804822
function deferHiddenOffscreenComponent(
805823
current: Fiber | null,
806824
workInProgress: Fiber,
@@ -1101,9 +1119,13 @@ function updateActivityComponent(
11011119
if (nextProps.mode === 'hidden') {
11021120
// SSR doesn't render hidden Activity so it shouldn't hydrate,
11031121
// even at offscreen lane. Defer to a client rendered offscreen lane.
1104-
mountActivityChildren(workInProgress, nextProps, renderLanes);
1122+
const primaryChildFragment = mountActivityChildren(
1123+
workInProgress,
1124+
nextProps,
1125+
renderLanes,
1126+
);
11051127
workInProgress.lanes = laneToLanes(OffscreenLane);
1106-
return null;
1128+
return bailoutOffscreenComponent(null, primaryChildFragment);
11071129
} else {
11081130
// We must push the suspense handler context *before* attempting to
11091131
// hydrate, to avoid a mismatch in case it errors.
@@ -2369,7 +2391,7 @@ function updateSuspenseComponent(
23692391
if (showFallback) {
23702392
pushFallbackTreeSuspenseHandler(workInProgress);
23712393

2372-
const fallbackFragment = mountSuspenseFallbackChildren(
2394+
mountSuspenseFallbackChildren(
23732395
workInProgress,
23742396
nextPrimaryChildren,
23752397
nextFallbackChildren,
@@ -2378,13 +2400,6 @@ function updateSuspenseComponent(
23782400
const primaryChildFragment: Fiber = (workInProgress.child: any);
23792401
primaryChildFragment.memoizedState =
23802402
mountSuspenseOffscreenState(renderLanes);
2381-
const primaryChildInstance = {
2382-
_visibility: OffscreenHidden,
2383-
_pendingMarkers: null,
2384-
_retryCache: null,
2385-
_transitions: null,
2386-
};
2387-
primaryChildFragment.stateNode = primaryChildInstance;
23882403
primaryChildFragment.childLanes = getRemainingWorkInPrimaryTree(
23892404
current,
23902405
didPrimaryChildrenDefer,
@@ -2411,7 +2426,7 @@ function updateSuspenseComponent(
24112426
}
24122427
}
24132428

2414-
return fallbackFragment;
2429+
return bailoutOffscreenComponent(null, primaryChildFragment);
24152430
} else if (
24162431
enableCPUSuspense &&
24172432
typeof nextProps.unstable_expectedLoadTime === 'number'
@@ -2420,7 +2435,7 @@ function updateSuspenseComponent(
24202435
// unblock the surrounding content. Then immediately retry after the
24212436
// initial commit.
24222437
pushFallbackTreeSuspenseHandler(workInProgress);
2423-
const fallbackFragment = mountSuspenseFallbackChildren(
2438+
mountSuspenseFallbackChildren(
24242439
workInProgress,
24252440
nextPrimaryChildren,
24262441
nextFallbackChildren,
@@ -2447,7 +2462,7 @@ function updateSuspenseComponent(
24472462
// RetryLane even if it's the one currently rendering since we're leaving
24482463
// it behind on this node.
24492464
workInProgress.lanes = SomeRetryLane;
2450-
return fallbackFragment;
2465+
return bailoutOffscreenComponent(null, primaryChildFragment);
24512466
} else {
24522467
pushPrimaryTreeSuspenseHandler(workInProgress);
24532468
return mountSuspensePrimaryChildren(
@@ -2482,7 +2497,7 @@ function updateSuspenseComponent(
24822497

24832498
const nextFallbackChildren = nextProps.fallback;
24842499
const nextPrimaryChildren = nextProps.children;
2485-
const fallbackChildFragment = updateSuspenseFallbackChildren(
2500+
updateSuspenseFallbackChildren(
24862501
current,
24872502
workInProgress,
24882503
nextPrimaryChildren,
@@ -2535,7 +2550,7 @@ function updateSuspenseComponent(
25352550
renderLanes,
25362551
);
25372552
workInProgress.memoizedState = SUSPENDED_MARKER;
2538-
return fallbackChildFragment;
2553+
return bailoutOffscreenComponent(current.child, primaryChildFragment);
25392554
} else {
25402555
pushPrimaryTreeSuspenseHandler(workInProgress);
25412556

@@ -2780,7 +2795,7 @@ function updateSuspenseFallbackChildren(
27802795
primaryChildFragment.sibling = fallbackChildFragment;
27812796
workInProgress.child = primaryChildFragment;
27822797

2783-
return fallbackChildFragment;
2798+
return bailoutOffscreenComponent(null, primaryChildFragment);
27842799
}
27852800

27862801
function retrySuspenseComponentWithoutHydrating(
@@ -2820,7 +2835,7 @@ function mountSuspenseFallbackAfterRetryWithoutHydrating(
28202835
) {
28212836
const fiberMode = workInProgress.mode;
28222837
const primaryChildProps: OffscreenProps = {
2823-
mode: 'hidden',
2838+
mode: 'visible',
28242839
children: primaryChildren,
28252840
};
28262841
const primaryChildFragment = mountWorkInProgressOffscreenFiber(
@@ -3095,7 +3110,7 @@ function updateDehydratedSuspenseComponent(
30953110
renderLanes,
30963111
);
30973112
workInProgress.memoizedState = SUSPENDED_MARKER;
3098-
return workInProgress.child;
3113+
return bailoutOffscreenComponent(null, primaryChildFragment);
30993114
}
31003115
}
31013116
}

packages/react-reconciler/src/ReactFiberOffscreenComponent.js

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,6 @@ export type OffscreenQueue = {
5050

5151
type OffscreenVisibility = number;
5252

53-
export const OffscreenHidden = /* */ 0b000;
5453
export const OffscreenVisible = /* */ 0b001;
5554
export const OffscreenPassiveEffectsConnected = /* */ 0b010;
5655

@@ -60,12 +59,3 @@ export type OffscreenInstance = {
6059
_transitions: Set<Transition> | null,
6160
_retryCache: WeakSet<Wakeable> | Set<Wakeable> | null,
6261
};
63-
64-
export function createInitialOffscreenInstance(): OffscreenInstance {
65-
return {
66-
_visibility: OffscreenVisible,
67-
_pendingMarkers: null,
68-
_retryCache: null,
69-
_transitions: null,
70-
};
71-
}

0 commit comments

Comments
 (0)