@samitouri / QOS-React-1 / commits / 99fd4f2ac1

[DevTools] Reorder moved filtered Fibers with backing DevToolsInstance (#34104)

Instead, we just continue to collect the unfiltered children. --------- Co-authored-by: Sebastian Sebbie Silbermann <sebastian.silbermann@vercel.com>

Sebastian Markbåge committed Aug 5, 2025 at 12:39 UTC 99fd4f2ac1fc9bd6b7aeb57afb2bcb1599ad1165
2 files changed +80
packages/react-devtools-shared/src/__tests__/store-test.js
+75
@@ -17,8 +17,10 @@ describe('Store', () => {
17 let act;
18 let actAsync;
19 let bridge;
20 + let createDisplayNameFilter;
21 let getRendererID;
22 let legacyRender;
23 + let previousComponentFilters;
24 let store;
25 let withErrorsOrWarningsIgnored;
26
@@ -29,6 +31,8 @@ describe('Store', () => {
31 bridge = global.bridge;
32 store = global.store;
33
34 + previousComponentFilters = store.componentFilters;
35 +
36 React = require('react');
37 ReactDOM = require('react-dom');
38 ReactDOMClient = require('react-dom/client');
@@ -38,9 +42,14 @@ describe('Store', () => {
42 actAsync = utils.actAsync;
43 getRendererID = utils.getRendererID;
44 legacyRender = utils.legacyRender;
45 + createDisplayNameFilter = utils.createDisplayNameFilter;
46 withErrorsOrWarningsIgnored = utils.withErrorsOrWarningsIgnored;
47 });
48
49 + afterEach(() => {
50 + store.componentFilters = previousComponentFilters;
51 + });
52 +
53 const {render, unmount, createContainer} = getVersionedRenderImplementation();
54
55 // @reactVersion >= 18.0
@@ -129,6 +138,72 @@ describe('Store', () => {
138 `);
139 });
140
141 + it('should handle reorder of filtered elements', async () => {
142 + function IgnoreMePassthrough({children}) {
143 + return children;
144 + }
145 + function PassThrough({children}) {
146 + return children;
147 + }
148 +
149 + await actAsync(
150 + async () =>
151 + (store.componentFilters = [createDisplayNameFilter('^IgnoreMe', true)]),
152 + );
153 +
154 + await act(() => {
155 + render(
156 + <PassThrough key="e" name="e">
157 + <IgnoreMePassthrough key="e1">
158 + <PassThrough name="e-child-one">
159 + <p>e1</p>
160 + </PassThrough>
161 + </IgnoreMePassthrough>
162 + <IgnoreMePassthrough key="e2">
163 + <PassThrough name="e-child-two">
164 + <div>e2</div>
165 + </PassThrough>
166 + </IgnoreMePassthrough>
167 + </PassThrough>,
168 + );
169 + });
170 +
171 + expect(store).toMatchInlineSnapshot(`
172 + [root]
173 + ▾ <PassThrough key="e">
174 + ▾ <PassThrough>
175 + <p>
176 + ▾ <PassThrough>
177 + <div>
178 + `);
179 +
180 + await act(() => {
181 + render(
182 + <PassThrough key="e" name="e">
183 + <IgnoreMePassthrough key="e2">
184 + <PassThrough name="e-child-two">
185 + <div>e2</div>
186 + </PassThrough>
187 + </IgnoreMePassthrough>
188 + <IgnoreMePassthrough key="e1">
189 + <PassThrough name="e-child-one">
190 + <p>e1</p>
191 + </PassThrough>
192 + </IgnoreMePassthrough>
193 + </PassThrough>,
194 + );
195 + });
196 +
197 + expect(store).toMatchInlineSnapshot(`
198 + [root]
199 + ▾ <PassThrough key="e">
200 + ▾ <PassThrough>
201 + <div>
202 + ▾ <PassThrough>
203 + <p>
204 + `);
205 + });
206 +
207 describe('StrictMode compliance', () => {
208 it('should mark strict root elements as strict', async () => {
209 const App = () => <Component />;
packages/react-devtools-shared/src/backend/fiber/renderer.js
+5
@@ -3612,6 +3612,11 @@ export function attach(
3612 shouldResetChildren = true;
3613 }
3614 } else if (prevChild !== null && shouldFilterFiber(nextChild)) {
3615 + // The filtered instance could've reordered.
3616 + if (prevChild !== prevChildAtSameIndex) {
3617 + shouldResetChildren = true;
3618 + }
3619 +
3620 // If this Fiber should be filtered, we need to still update its children.
3621 // This relies on an alternate since we don't have an Instance with the previous
3622 // child on it. Ideally, the reconciliation wouldn't need previous Fibers that