diff --git a/packages/react-devtools-shared/src/__tests__/profilingCache-test.js b/packages/react-devtools-shared/src/__tests__/profilingCache-test.js index 0d26d7107cb6d..428b22d466d79 100644 --- a/packages/react-devtools-shared/src/__tests__/profilingCache-test.js +++ b/packages/react-devtools-shared/src/__tests__/profilingCache-test.js @@ -725,14 +725,14 @@ describe('ProfilingCache', () => { const commitData = store.profilerStore.getDataForRoot(rootID).commitData; expect(commitData).toHaveLength(2); - const isLegacySuspense = React.version.startsWith('17'); - if (isLegacySuspense) { + if (React.version.startsWith('17')) { + // React 17 will mount all children until it suspends in a LegacyHidden + // The ID gap is from the Fiber for that's in the disconnected tree. expect(commitData[0].fiberActualDurations).toMatchInlineSnapshot(` Map { 1 => 15, 2 => 15, 3 => 5, - 4 => 3, 5 => 2, } `); @@ -741,7 +741,6 @@ describe('ProfilingCache', () => { 1 => 0, 2 => 10, 3 => 3, - 4 => 3, 5 => 2, } `); diff --git a/packages/react-devtools-shared/src/__tests__/profilingCommitTreeBuilder-test.js b/packages/react-devtools-shared/src/__tests__/profilingCommitTreeBuilder-test.js index 176056cf10e63..968fda10dab5f 100644 --- a/packages/react-devtools-shared/src/__tests__/profilingCommitTreeBuilder-test.js +++ b/packages/react-devtools-shared/src/__tests__/profilingCommitTreeBuilder-test.js @@ -19,8 +19,6 @@ describe('commit tree', () => { let Scheduler; let store: Store; let utils; - const isLegacySuspense = - React.version.startsWith('16') || React.version.startsWith('17'); beforeEach(() => { utils = require('./utils'); @@ -186,24 +184,13 @@ describe('commit tree', () => { utils.act(() => store.profilerStore.startProfiling()); utils.act(() => legacyRender()); await Promise.resolve(); - if (isLegacySuspense) { - expect(store).toMatchInlineSnapshot(` - [root] - ▾ - ▾ - - [suspense-root] rects={null} - - `); - } else { - expect(store).toMatchInlineSnapshot(` - [root] - ▾ - - [suspense-root] rects={null} - - `); - } + expect(store).toMatchInlineSnapshot(` + [root] + ▾ + + [suspense-root] rects={null} + + `); utils.act(() => legacyRender()); expect(store).toMatchInlineSnapshot(` [root] @@ -231,13 +218,7 @@ describe('commit tree', () => { ); } - expect(commitTrees[0].nodes.size).toBe( - isLegacySuspense - ? // + + + - 4 - : // + + - 3, - ); + expect(commitTrees[0].nodes.size).toBe(3); expect(commitTrees[1].nodes.size).toBe(4); // + + + expect(commitTrees[2].nodes.size).toBe(2); // + }); @@ -291,24 +272,13 @@ describe('commit tree', () => { it('should support Lazy components that are unmounted before resolving (legacy render)', async () => { utils.act(() => store.profilerStore.startProfiling()); utils.act(() => legacyRender()); - if (isLegacySuspense) { - expect(store).toMatchInlineSnapshot(` - [root] - ▾ - ▾ - - [suspense-root] rects={null} - - `); - } else { - expect(store).toMatchInlineSnapshot(` - [root] - ▾ - - [suspense-root] rects={null} - - `); - } + expect(store).toMatchInlineSnapshot(` + [root] + ▾ + + [suspense-root] rects={null} + + `); utils.act(() => legacyRender()); expect(store).toMatchInlineSnapshot(` [root] @@ -327,13 +297,7 @@ describe('commit tree', () => { ); } - expect(commitTrees[0].nodes.size).toBe( - isLegacySuspense - ? // + + + - 4 - : // + + - 3, - ); + expect(commitTrees[0].nodes.size).toBe(3); expect(commitTrees[1].nodes.size).toBe(2); // + }); diff --git a/packages/react-devtools-shared/src/__tests__/store-test.js b/packages/react-devtools-shared/src/__tests__/store-test.js index a2024be3d2e5e..4d4d5b6affc4f 100644 --- a/packages/react-devtools-shared/src/__tests__/store-test.js +++ b/packages/react-devtools-shared/src/__tests__/store-test.js @@ -2828,7 +2828,7 @@ describe('Store', () => { `); }); - // @reactVersion >= 18.0 + // @reactVersion >= 17.0 it('can reconcile Suspense in fallback positions', async () => { let resolveFallback; const fallbackPromise = new Promise(resolve => { @@ -2907,7 +2907,7 @@ describe('Store', () => { `); }); - // @reactVersion >= 18.0 + // @reactVersion >= 17.0 it('can reconcile resuspended Suspense with Suspense in fallback positions', async () => { let resolveHeadFallback; let resolveHeadContent; diff --git a/packages/react-devtools-shared/src/backend/fiber/renderer.js b/packages/react-devtools-shared/src/backend/fiber/renderer.js index 33786a41877b8..39179bc6f472f 100644 --- a/packages/react-devtools-shared/src/backend/fiber/renderer.js +++ b/packages/react-devtools-shared/src/backend/fiber/renderer.js @@ -460,10 +460,10 @@ export function getInternalReactConstants(version: string): { IncompleteFunctionComponent: 28, IndeterminateComponent: 2, // removed in 19.0.0 LazyComponent: 16, - LegacyHiddenComponent: 23, + LegacyHiddenComponent: 23, // Does not exist in 18+ OSS but exists in fb builds MemoComponent: 14, Mode: 8, - OffscreenComponent: 22, // Experimental + OffscreenComponent: 22, // Experimental in 17. Stable in 18+ Profiler: 12, ScopeComponent: 21, // Experimental SimpleMemoComponent: 15, @@ -3057,13 +3057,23 @@ export function attach( } } + function isHiddenOffscreen(fiber: Fiber): boolean { + switch (fiber.tag) { + case LegacyHiddenComponent: + // fallthrough since all published implementations currently implement the same state as Offscreen. + case OffscreenComponent: + return fiber.memoizedState !== null; + default: + return false; + } + } + function unmountRemainingChildren() { if ( reconcilingParent !== null && (reconcilingParent.kind === FIBER_INSTANCE || reconcilingParent.kind === FILTERED_FIBER_INSTANCE) && - reconcilingParent.data.tag === OffscreenComponent && - reconcilingParent.data.memoizedState !== null && + isHiddenOffscreen(reconcilingParent.data) && !isInDisconnectedSubtree ) { // This is a hidden offscreen, we need to execute this in the context of a disconnected subtree. @@ -3170,8 +3180,7 @@ export function attach( if ( (parent.kind === FIBER_INSTANCE || parent.kind === FILTERED_FIBER_INSTANCE) && - parent.data.tag === OffscreenComponent && - parent.data.memoizedState !== null + isHiddenOffscreen(parent.data) ) { // We're inside a hidden offscreen Fiber. We're in a disconnected tree. return; @@ -3819,7 +3828,9 @@ export function attach( (reconcilingParent !== null && reconcilingParent.kind === VIRTUAL_INSTANCE) || fiber.tag === SuspenseComponent || - fiber.tag === OffscreenComponent // Use to keep resuspended instances alive inside a SuspenseComponent. + // Use to keep resuspended instances alive inside a SuspenseComponent. + fiber.tag === OffscreenComponent || + fiber.tag === LegacyHiddenComponent ) { // If the parent is a Virtual Instance and we filtered this Fiber we include a // hidden node. We also include this if it's a Suspense boundary so we can track those @@ -3939,7 +3950,7 @@ export function attach( trackDebugInfoFromHostComponent(nearestInstance, fiber); } - if (fiber.tag === OffscreenComponent && fiber.memoizedState !== null) { + if (isHiddenOffscreen(fiber)) { // If an Offscreen component is hidden, mount its children as disconnected. const stashedDisconnected = isInDisconnectedSubtree; isInDisconnectedSubtree = true; @@ -4261,7 +4272,7 @@ export function attach( while (child !== null) { if (child.kind === FILTERED_FIBER_INSTANCE) { const fiber = child.data; - if (fiber.tag === OffscreenComponent && fiber.memoizedState !== null) { + if (isHiddenOffscreen(fiber)) { // The children of this Offscreen are hidden so they don't get added. } else { addUnfilteredChildrenIDs(child, nextChildren); @@ -4888,9 +4899,8 @@ export function attach( const nextDidTimeOut = isLegacySuspense && nextFiber.memoizedState !== null; - const isOffscreen = nextFiber.tag === OffscreenComponent; - const prevWasHidden = isOffscreen && prevFiber.memoizedState !== null; - const nextIsHidden = isOffscreen && nextFiber.memoizedState !== null; + const prevWasHidden = isHiddenOffscreen(prevFiber); + const nextIsHidden = isHiddenOffscreen(nextFiber); if (isLegacySuspense) { if ( @@ -5245,8 +5255,7 @@ export function attach( if ( (child.kind === FIBER_INSTANCE || child.kind === FILTERED_FIBER_INSTANCE) && - child.data.tag === OffscreenComponent && - child.data.memoizedState !== null + isHiddenOffscreen(child.data) ) { // This instance's children are already disconnected. } else { @@ -5275,8 +5284,7 @@ export function attach( if ( (child.kind === FIBER_INSTANCE || child.kind === FILTERED_FIBER_INSTANCE) && - child.data.tag === OffscreenComponent && - child.data.memoizedState !== null + isHiddenOffscreen(child.data) ) { // This instance's children should remain disconnected. } else {