diff --git a/packages/react-devtools-shared/src/__tests__/store-test.js b/packages/react-devtools-shared/src/__tests__/store-test.js index e982ac5ecc5cd..1a5a0e6a26070 100644 --- a/packages/react-devtools-shared/src/__tests__/store-test.js +++ b/packages/react-devtools-shared/src/__tests__/store-test.js @@ -17,8 +17,10 @@ describe('Store', () => { let act; let actAsync; let bridge; + let createDisplayNameFilter; let getRendererID; let legacyRender; + let previousComponentFilters; let store; let withErrorsOrWarningsIgnored; @@ -29,6 +31,8 @@ describe('Store', () => { bridge = global.bridge; store = global.store; + previousComponentFilters = store.componentFilters; + React = require('react'); ReactDOM = require('react-dom'); ReactDOMClient = require('react-dom/client'); @@ -38,9 +42,14 @@ describe('Store', () => { actAsync = utils.actAsync; getRendererID = utils.getRendererID; legacyRender = utils.legacyRender; + createDisplayNameFilter = utils.createDisplayNameFilter; withErrorsOrWarningsIgnored = utils.withErrorsOrWarningsIgnored; }); + afterEach(() => { + store.componentFilters = previousComponentFilters; + }); + const {render, unmount, createContainer} = getVersionedRenderImplementation(); // @reactVersion >= 18.0 @@ -129,6 +138,72 @@ describe('Store', () => { `); }); + it('should handle reorder of filtered elements', async () => { + function IgnoreMePassthrough({children}) { + return children; + } + function PassThrough({children}) { + return children; + } + + await actAsync( + async () => + (store.componentFilters = [createDisplayNameFilter('^IgnoreMe', true)]), + ); + + await act(() => { + render( + + + +

e1

+
+
+ + +
e2
+
+
+
, + ); + }); + + expect(store).toMatchInlineSnapshot(` + [root] + ▾ + ▾ +

+ ▾ +

+ `); + + await act(() => { + render( + + + +
e2
+
+
+ + +

e1

+
+
+
, + ); + }); + + expect(store).toMatchInlineSnapshot(` + [root] + ▾ + ▾ +
+ ▾ +

+ `); + }); + describe('StrictMode compliance', () => { it('should mark strict root elements as strict', async () => { const App = () => ; diff --git a/packages/react-devtools-shared/src/backend/fiber/renderer.js b/packages/react-devtools-shared/src/backend/fiber/renderer.js index b6bc24dd01b4c..2a41f6e08f096 100644 --- a/packages/react-devtools-shared/src/backend/fiber/renderer.js +++ b/packages/react-devtools-shared/src/backend/fiber/renderer.js @@ -3612,6 +3612,11 @@ export function attach( shouldResetChildren = true; } } else if (prevChild !== null && shouldFilterFiber(nextChild)) { + // The filtered instance could've reordered. + if (prevChild !== prevChildAtSameIndex) { + shouldResetChildren = true; + } + // If this Fiber should be filtered, we need to still update its children. // This relies on an alternate since we don't have an Instance with the previous // child on it. Ideally, the reconciliation wouldn't need previous Fibers that