diff --git a/packages/react-devtools-shared/src/__tests__/__snapshots__/storeComponentFilters-test.js.snap b/packages/react-devtools-shared/src/__tests__/__snapshots__/storeComponentFilters-test.js.snap index cfe68aa69ecbc..49035b9927836 100644 --- a/packages/react-devtools-shared/src/__tests__/__snapshots__/storeComponentFilters-test.js.snap +++ b/packages/react-devtools-shared/src/__tests__/__snapshots__/storeComponentFilters-test.js.snap @@ -97,6 +97,13 @@ exports[`Store component filters should not break when Suspense nodes are filter `; +exports[`Store component filters should not break when Suspense nodes are filtered from the tree: 3: suspended 1`] = ` +[root] + ▾ + ▾ +
+`; + exports[`Store component filters should support filtering by element type: 1: mount 1`] = ` [root] ▾ diff --git a/packages/react-devtools-shared/src/__tests__/storeComponentFilters-test.js b/packages/react-devtools-shared/src/__tests__/storeComponentFilters-test.js index bfbf3e98210a9..a8a0e151ef748 100644 --- a/packages/react-devtools-shared/src/__tests__/storeComponentFilters-test.js +++ b/packages/react-devtools-shared/src/__tests__/storeComponentFilters-test.js @@ -256,5 +256,8 @@ describe('Store component filters', () => { act(() => ReactDOM.render(, container)); expect(store).toMatchSnapshot('2: resolved'); + + act(() => ReactDOM.render(, container)); + expect(store).toMatchSnapshot('3: suspended'); }); }); diff --git a/packages/react-devtools-shared/src/backend/renderer.js b/packages/react-devtools-shared/src/backend/renderer.js index c10d71bbfec2e..23deda7dde258 100644 --- a/packages/react-devtools-shared/src/backend/renderer.js +++ b/packages/react-devtools-shared/src/backend/renderer.js @@ -1437,6 +1437,9 @@ export function attach( } function recordResetChildren(fiber: Fiber, childSet: Fiber) { + if (__DEBUG__) { + debug('recordResetChildren()', childSet, fiber); + } // The frontend only really cares about the displayName, key, and children. // The first two don't really change, so we are only concerned with the order of children here. // This is trickier than a simple comparison though, since certain types of fibers are filtered. @@ -1471,6 +1474,23 @@ export function attach( nextChildren.push(getFiberID(getPrimaryFiber(fiber))); } else { let child = fiber.child; + const isTimedOutSuspense = + fiber.tag === SuspenseComponent && fiber.memoizedState !== null; + if (isTimedOutSuspense) { + // Special case: if Suspense mounts in a timed-out state, + // get the fallback child from the inner fragment, + // and skip over the primary child. + const primaryChildFragment = fiber.child; + const fallbackChildFragment = primaryChildFragment + ? primaryChildFragment.sibling + : null; + const fallbackChild = fallbackChildFragment + ? fallbackChildFragment.child + : null; + if (fallbackChild !== null) { + child = fallbackChild; + } + } while (child !== null) { findReorderedChildrenRecursively(child, nextChildren); child = child.sibling; @@ -1592,7 +1612,7 @@ export function attach( if (nextFallbackChildSet != null) { mountFiberRecursively( nextFallbackChildSet, - nextFiber, + shouldIncludeInTree ? nextFiber : parentFiber, true, traceNearestHostComponentUpdate, );