Skip to content

Commit f7e2e5f

Browse files
committed
[DevTools] Handle LegacyHidden Fibers like Offscreen Fibers.
This is mostly for React 17 which uses `LegacyHiddenComponent` instead of `Offscreen` for the content Fiber.
1 parent cad813a commit f7e2e5f

File tree

4 files changed

+45
-74
lines changed

4 files changed

+45
-74
lines changed

packages/react-devtools-shared/src/__tests__/profilingCache-test.js

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -725,14 +725,13 @@ describe('ProfilingCache', () => {
725725
const commitData = store.profilerStore.getDataForRoot(rootID).commitData;
726726
expect(commitData).toHaveLength(2);
727727

728-
const isLegacySuspense = React.version.startsWith('17');
729-
if (isLegacySuspense) {
728+
const suspenseUsesLegacyHidden = React.version.startsWith('17');
729+
if (suspenseUsesLegacyHidden) {
730730
expect(commitData[0].fiberActualDurations).toMatchInlineSnapshot(`
731731
Map {
732732
1 => 15,
733733
2 => 15,
734734
3 => 5,
735-
4 => 3,
736735
5 => 2,
737736
}
738737
`);
@@ -741,7 +740,6 @@ describe('ProfilingCache', () => {
741740
1 => 0,
742741
2 => 10,
743742
3 => 3,
744-
4 => 3,
745743
5 => 2,
746744
}
747745
`);

packages/react-devtools-shared/src/__tests__/profilingCommitTreeBuilder-test.js

Lines changed: 16 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,6 @@ describe('commit tree', () => {
1919
let Scheduler;
2020
let store: Store;
2121
let utils;
22-
const isLegacySuspense =
23-
React.version.startsWith('16') || React.version.startsWith('17');
2422

2523
beforeEach(() => {
2624
utils = require('./utils');
@@ -186,24 +184,13 @@ describe('commit tree', () => {
186184
utils.act(() => store.profilerStore.startProfiling());
187185
utils.act(() => legacyRender(<App renderChildren={true} />));
188186
await Promise.resolve();
189-
if (isLegacySuspense) {
190-
expect(store).toMatchInlineSnapshot(`
191-
[root]
192-
▾ <App>
193-
▾ <Suspense>
194-
<Lazy>
195-
[suspense-root] rects={null}
196-
<Suspense name="App" rects={null}>
197-
`);
198-
} else {
199-
expect(store).toMatchInlineSnapshot(`
200-
[root]
201-
▾ <App>
202-
<Suspense>
203-
[suspense-root] rects={null}
204-
<Suspense name="App" rects={null}>
205-
`);
206-
}
187+
expect(store).toMatchInlineSnapshot(`
188+
[root]
189+
▾ <App>
190+
<Suspense>
191+
[suspense-root] rects={null}
192+
<Suspense name="App" rects={null}>
193+
`);
207194
utils.act(() => legacyRender(<App renderChildren={true} />));
208195
expect(store).toMatchInlineSnapshot(`
209196
[root]
@@ -231,13 +218,7 @@ describe('commit tree', () => {
231218
);
232219
}
233220

234-
expect(commitTrees[0].nodes.size).toBe(
235-
isLegacySuspense
236-
? // <Root> + <App> + <Suspense> + <Lazy>
237-
4
238-
: // <Root> + <App> + <Suspense>
239-
3,
240-
);
221+
expect(commitTrees[0].nodes.size).toBe(3);
241222
expect(commitTrees[1].nodes.size).toBe(4); // <Root> + <App> + <Suspense> + <LazyInnerComponent>
242223
expect(commitTrees[2].nodes.size).toBe(2); // <Root> + <App>
243224
});
@@ -291,24 +272,13 @@ describe('commit tree', () => {
291272
it('should support Lazy components that are unmounted before resolving (legacy render)', async () => {
292273
utils.act(() => store.profilerStore.startProfiling());
293274
utils.act(() => legacyRender(<App renderChildren={true} />));
294-
if (isLegacySuspense) {
295-
expect(store).toMatchInlineSnapshot(`
296-
[root]
297-
▾ <App>
298-
▾ <Suspense>
299-
<Lazy>
300-
[suspense-root] rects={null}
301-
<Suspense name="App" rects={null}>
302-
`);
303-
} else {
304-
expect(store).toMatchInlineSnapshot(`
305-
[root]
306-
▾ <App>
307-
<Suspense>
308-
[suspense-root] rects={null}
309-
<Suspense name="App" rects={null}>
310-
`);
311-
}
275+
expect(store).toMatchInlineSnapshot(`
276+
[root]
277+
▾ <App>
278+
<Suspense>
279+
[suspense-root] rects={null}
280+
<Suspense name="App" rects={null}>
281+
`);
312282
utils.act(() => legacyRender(<App renderChildren={false} />));
313283
expect(store).toMatchInlineSnapshot(`
314284
[root]
@@ -327,13 +297,7 @@ describe('commit tree', () => {
327297
);
328298
}
329299

330-
expect(commitTrees[0].nodes.size).toBe(
331-
isLegacySuspense
332-
? // <Root> + <App> + <Suspense> + <Lazy>
333-
4
334-
: // <Root> + <App> + <Suspense>
335-
3,
336-
);
300+
expect(commitTrees[0].nodes.size).toBe(3);
337301
expect(commitTrees[1].nodes.size).toBe(2); // <Root> + <App>
338302
});
339303

packages/react-devtools-shared/src/__tests__/store-test.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2828,7 +2828,7 @@ describe('Store', () => {
28282828
`);
28292829
});
28302830

2831-
// @reactVersion >= 18.0
2831+
// @reactVersion >= 17.0
28322832
it('can reconcile Suspense in fallback positions', async () => {
28332833
let resolveFallback;
28342834
const fallbackPromise = new Promise(resolve => {
@@ -2907,7 +2907,7 @@ describe('Store', () => {
29072907
`);
29082908
});
29092909

2910-
// @reactVersion >= 18.0
2910+
// @reactVersion >= 17.0
29112911
it('can reconcile resuspended Suspense with Suspense in fallback positions', async () => {
29122912
let resolveHeadFallback;
29132913
let resolveHeadContent;

packages/react-devtools-shared/src/backend/fiber/renderer.js

Lines changed: 25 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -460,10 +460,11 @@ export function getInternalReactConstants(version: string): {
460460
IncompleteFunctionComponent: 28,
461461
IndeterminateComponent: 2, // removed in 19.0.0
462462
LazyComponent: 16,
463-
LegacyHiddenComponent: 23,
463+
LegacyHiddenComponent: 23, // Does not exist in 18+ OSS but exists in fb builds
464464
MemoComponent: 14,
465465
Mode: 8,
466-
OffscreenComponent: 22, // Experimental
466+
OffscreenComponent: 22, // Experimental - This is technically in 18 but we don't
467+
// want to fork again so we're adding it here instead
467468
Profiler: 12,
468469
ScopeComponent: 21, // Experimental
469470
SimpleMemoComponent: 15,
@@ -3057,13 +3058,23 @@ export function attach(
30573058
}
30583059
}
30593060
3061+
function isHiddenOffscreen(fiber: Fiber): boolean {
3062+
switch (fiber.tag) {
3063+
case LegacyHiddenComponent:
3064+
// fallthrough since all published implementations currently implement the same state as Offscreen.
3065+
case OffscreenComponent:
3066+
return fiber.memoizedState !== null;
3067+
default:
3068+
return false;
3069+
}
3070+
}
3071+
30603072
function unmountRemainingChildren() {
30613073
if (
30623074
reconcilingParent !== null &&
30633075
(reconcilingParent.kind === FIBER_INSTANCE ||
30643076
reconcilingParent.kind === FILTERED_FIBER_INSTANCE) &&
3065-
reconcilingParent.data.tag === OffscreenComponent &&
3066-
reconcilingParent.data.memoizedState !== null &&
3077+
isHiddenOffscreen(reconcilingParent.data) &&
30673078
!isInDisconnectedSubtree
30683079
) {
30693080
// This is a hidden offscreen, we need to execute this in the context of a disconnected subtree.
@@ -3170,8 +3181,7 @@ export function attach(
31703181
if (
31713182
(parent.kind === FIBER_INSTANCE ||
31723183
parent.kind === FILTERED_FIBER_INSTANCE) &&
3173-
parent.data.tag === OffscreenComponent &&
3174-
parent.data.memoizedState !== null
3184+
isHiddenOffscreen(parent.data)
31753185
) {
31763186
// We're inside a hidden offscreen Fiber. We're in a disconnected tree.
31773187
return;
@@ -3819,7 +3829,9 @@ export function attach(
38193829
(reconcilingParent !== null &&
38203830
reconcilingParent.kind === VIRTUAL_INSTANCE) ||
38213831
fiber.tag === SuspenseComponent ||
3822-
fiber.tag === OffscreenComponent // Use to keep resuspended instances alive inside a SuspenseComponent.
3832+
// Use to keep resuspended instances alive inside a SuspenseComponent.
3833+
fiber.tag === OffscreenComponent ||
3834+
fiber.tag === LegacyHiddenComponent
38233835
) {
38243836
// If the parent is a Virtual Instance and we filtered this Fiber we include a
38253837
// hidden node. We also include this if it's a Suspense boundary so we can track those
@@ -3939,7 +3951,7 @@ export function attach(
39393951
trackDebugInfoFromHostComponent(nearestInstance, fiber);
39403952
}
39413953
3942-
if (fiber.tag === OffscreenComponent && fiber.memoizedState !== null) {
3954+
if (isHiddenOffscreen(fiber)) {
39433955
// If an Offscreen component is hidden, mount its children as disconnected.
39443956
const stashedDisconnected = isInDisconnectedSubtree;
39453957
isInDisconnectedSubtree = true;
@@ -4261,7 +4273,7 @@ export function attach(
42614273
while (child !== null) {
42624274
if (child.kind === FILTERED_FIBER_INSTANCE) {
42634275
const fiber = child.data;
4264-
if (fiber.tag === OffscreenComponent && fiber.memoizedState !== null) {
4276+
if (isHiddenOffscreen(fiber)) {
42654277
// The children of this Offscreen are hidden so they don't get added.
42664278
} else {
42674279
addUnfilteredChildrenIDs(child, nextChildren);
@@ -4888,9 +4900,8 @@ export function attach(
48884900
const nextDidTimeOut =
48894901
isLegacySuspense && nextFiber.memoizedState !== null;
48904902
4891-
const isOffscreen = nextFiber.tag === OffscreenComponent;
4892-
const prevWasHidden = isOffscreen && prevFiber.memoizedState !== null;
4893-
const nextIsHidden = isOffscreen && nextFiber.memoizedState !== null;
4903+
const prevWasHidden = isHiddenOffscreen(prevFiber);
4904+
const nextIsHidden = isHiddenOffscreen(nextFiber);
48944905
48954906
if (isLegacySuspense) {
48964907
if (
@@ -5245,8 +5256,7 @@ export function attach(
52455256
if (
52465257
(child.kind === FIBER_INSTANCE ||
52475258
child.kind === FILTERED_FIBER_INSTANCE) &&
5248-
child.data.tag === OffscreenComponent &&
5249-
child.data.memoizedState !== null
5259+
isHiddenOffscreen(child.data)
52505260
) {
52515261
// This instance's children are already disconnected.
52525262
} else {
@@ -5275,8 +5285,7 @@ export function attach(
52755285
if (
52765286
(child.kind === FIBER_INSTANCE ||
52775287
child.kind === FILTERED_FIBER_INSTANCE) &&
5278-
child.data.tag === OffscreenComponent &&
5279-
child.data.memoizedState !== null
5288+
isHiddenOffscreen(child.data)
52805289
) {
52815290
// This instance's children should remain disconnected.
52825291
} else {

0 commit comments

Comments
 (0)