@samitouri / QOS-React-2 / commits / 4053c76b7d

Add more DevTools tests for React.Lazy (#20380)

Brian Vaughn committed Dec 6, 2020 at 09:10 UTC 4053c76b7d0fd230517ba26c71a9550ac3346c88
5 files changed +709 -21
packages/react-devtools-shared/src/__tests__/__snapshots__/profilingCommitTreeBuilder-test.js.snap
+336
@@ -1,5 +1,341 @@
1 // Jest Snapshot v1, https://goo.gl/fbAQLP
2
3 +exports[`commit tree Lazy should support Lazy components (createRoot): 0: CommitTree 1`] = `
4 +Object {
5 + "nodes": Map {
6 + 1 => Object {
7 + "children": Array [
8 + 2,
9 + ],
10 + "displayName": null,
11 + "hocDisplayNames": null,
12 + "id": 1,
13 + "key": null,
14 + "parentID": 0,
15 + "treeBaseDuration": 0,
16 + "type": 11,
17 + },
18 + 2 => Object {
19 + "children": Array [
20 + 3,
21 + ],
22 + "displayName": "App",
23 + "hocDisplayNames": null,
24 + "id": 2,
25 + "key": null,
26 + "parentID": 1,
27 + "treeBaseDuration": 0,
28 + "type": 5,
29 + },
30 + 3 => Object {
31 + "children": Array [],
32 + "displayName": "Suspense",
33 + "hocDisplayNames": null,
34 + "id": 3,
35 + "key": null,
36 + "parentID": 2,
37 + "treeBaseDuration": 0,
38 + "type": 12,
39 + },
40 + },
41 + "rootID": 1,
42 +}
43 +`;
44 +
45 +exports[`commit tree Lazy should support Lazy components (createRoot): 1: CommitTree 1`] = `
46 +Object {
47 + "nodes": Map {
48 + 1 => Object {
49 + "children": Array [
50 + 2,
51 + ],
52 + "displayName": null,
53 + "hocDisplayNames": null,
54 + "id": 1,
55 + "key": null,
56 + "parentID": 0,
57 + "treeBaseDuration": 0,
58 + "type": 11,
59 + },
60 + 2 => Object {
61 + "children": Array [
62 + 3,
63 + ],
64 + "displayName": "App",
65 + "hocDisplayNames": null,
66 + "id": 2,
67 + "key": null,
68 + "parentID": 1,
69 + "treeBaseDuration": 0,
70 + "type": 5,
71 + },
72 + 3 => Object {
73 + "children": Array [
74 + 4,
75 + ],
76 + "displayName": "Suspense",
77 + "hocDisplayNames": null,
78 + "id": 3,
79 + "key": null,
80 + "parentID": 2,
81 + "treeBaseDuration": 0,
82 + "type": 12,
83 + },
84 + 4 => Object {
85 + "children": Array [],
86 + "displayName": "LazyInnerComponent",
87 + "hocDisplayNames": null,
88 + "id": 4,
89 + "key": null,
90 + "parentID": 3,
91 + "treeBaseDuration": 0,
92 + "type": 5,
93 + },
94 + },
95 + "rootID": 1,
96 +}
97 +`;
98 +
99 +exports[`commit tree Lazy should support Lazy components (legacy render): 0: CommitTree 1`] = `
100 +Object {
101 + "nodes": Map {
102 + 1 => Object {
103 + "children": Array [
104 + 2,
105 + ],
106 + "displayName": null,
107 + "hocDisplayNames": null,
108 + "id": 1,
109 + "key": null,
110 + "parentID": 0,
111 + "treeBaseDuration": 0,
112 + "type": 11,
113 + },
114 + 2 => Object {
115 + "children": Array [
116 + 3,
117 + ],
118 + "displayName": "App",
119 + "hocDisplayNames": null,
120 + "id": 2,
121 + "key": null,
122 + "parentID": 1,
123 + "treeBaseDuration": 0,
124 + "type": 5,
125 + },
126 + 3 => Object {
127 + "children": Array [],
128 + "displayName": "Suspense",
129 + "hocDisplayNames": null,
130 + "id": 3,
131 + "key": null,
132 + "parentID": 2,
133 + "treeBaseDuration": 0,
134 + "type": 12,
135 + },
136 + },
137 + "rootID": 1,
138 +}
139 +`;
140 +
141 +exports[`commit tree Lazy should support Lazy components (legacy render): 1: CommitTree 1`] = `
142 +Object {
143 + "nodes": Map {
144 + 1 => Object {
145 + "children": Array [
146 + 2,
147 + ],
148 + "displayName": null,
149 + "hocDisplayNames": null,
150 + "id": 1,
151 + "key": null,
152 + "parentID": 0,
153 + "treeBaseDuration": 0,
154 + "type": 11,
155 + },
156 + 2 => Object {
157 + "children": Array [
158 + 3,
159 + ],
160 + "displayName": "App",
161 + "hocDisplayNames": null,
162 + "id": 2,
163 + "key": null,
164 + "parentID": 1,
165 + "treeBaseDuration": 0,
166 + "type": 5,
167 + },
168 + 3 => Object {
169 + "children": Array [
170 + 4,
171 + ],
172 + "displayName": "Suspense",
173 + "hocDisplayNames": null,
174 + "id": 3,
175 + "key": null,
176 + "parentID": 2,
177 + "treeBaseDuration": 0,
178 + "type": 12,
179 + },
180 + 4 => Object {
181 + "children": Array [],
182 + "displayName": "LazyInnerComponent",
183 + "hocDisplayNames": null,
184 + "id": 4,
185 + "key": null,
186 + "parentID": 3,
187 + "treeBaseDuration": 0,
188 + "type": 5,
189 + },
190 + },
191 + "rootID": 1,
192 +}
193 +`;
194 +
195 +exports[`commit tree Lazy should support Lazy components that are unmounted before resolving (createRoot): 0: CommitTree 1`] = `
196 +Object {
197 + "nodes": Map {
198 + 1 => Object {
199 + "children": Array [
200 + 2,
201 + ],
202 + "displayName": null,
203 + "hocDisplayNames": null,
204 + "id": 1,
205 + "key": null,
206 + "parentID": 0,
207 + "treeBaseDuration": 0,
208 + "type": 11,
209 + },
210 + 2 => Object {
211 + "children": Array [
212 + 3,
213 + ],
214 + "displayName": "App",
215 + "hocDisplayNames": null,
216 + "id": 2,
217 + "key": null,
218 + "parentID": 1,
219 + "treeBaseDuration": 0,
220 + "type": 5,
221 + },
222 + 3 => Object {
223 + "children": Array [],
224 + "displayName": "Suspense",
225 + "hocDisplayNames": null,
226 + "id": 3,
227 + "key": null,
228 + "parentID": 2,
229 + "treeBaseDuration": 0,
230 + "type": 12,
231 + },
232 + },
233 + "rootID": 1,
234 +}
235 +`;
236 +
237 +exports[`commit tree Lazy should support Lazy components that are unmounted before resolving (createRoot): 1: CommitTree 1`] = `
238 +Object {
239 + "nodes": Map {
240 + 1 => Object {
241 + "children": Array [
242 + 2,
243 + ],
244 + "displayName": null,
245 + "hocDisplayNames": null,
246 + "id": 1,
247 + "key": null,
248 + "parentID": 0,
249 + "treeBaseDuration": 0,
250 + "type": 11,
251 + },
252 + 2 => Object {
253 + "children": Array [],
254 + "displayName": "App",
255 + "hocDisplayNames": null,
256 + "id": 2,
257 + "key": null,
258 + "parentID": 1,
259 + "treeBaseDuration": 0,
260 + "type": 5,
261 + },
262 + },
263 + "rootID": 1,
264 +}
265 +`;
266 +
267 +exports[`commit tree Lazy should support Lazy components that are unmounted before resolving (legacy render): 0: CommitTree 1`] = `
268 +Object {
269 + "nodes": Map {
270 + 1 => Object {
271 + "children": Array [
272 + 2,
273 + ],
274 + "displayName": null,
275 + "hocDisplayNames": null,
276 + "id": 1,
277 + "key": null,
278 + "parentID": 0,
279 + "treeBaseDuration": 0,
280 + "type": 11,
281 + },
282 + 2 => Object {
283 + "children": Array [
284 + 3,
285 + ],
286 + "displayName": "App",
287 + "hocDisplayNames": null,
288 + "id": 2,
289 + "key": null,
290 + "parentID": 1,
291 + "treeBaseDuration": 0,
292 + "type": 5,
293 + },
294 + 3 => Object {
295 + "children": Array [],
296 + "displayName": "Suspense",
297 + "hocDisplayNames": null,
298 + "id": 3,
299 + "key": null,
300 + "parentID": 2,
301 + "treeBaseDuration": 0,
302 + "type": 12,
303 + },
304 + },
305 + "rootID": 1,
306 +}
307 +`;
308 +
309 +exports[`commit tree Lazy should support Lazy components that are unmounted before resolving (legacy render): 1: CommitTree 1`] = `
310 +Object {
311 + "nodes": Map {
312 + 1 => Object {
313 + "children": Array [
314 + 2,
315 + ],
316 + "displayName": null,
317 + "hocDisplayNames": null,
318 + "id": 1,
319 + "key": null,
320 + "parentID": 0,
321 + "treeBaseDuration": 0,
322 + "type": 11,
323 + },
324 + 2 => Object {
325 + "children": Array [],
326 + "displayName": "App",
327 + "hocDisplayNames": null,
328 + "id": 2,
329 + "key": null,
330 + "parentID": 1,
331 + "treeBaseDuration": 0,
332 + "type": 5,
333 + },
334 + },
335 + "rootID": 1,
336 +}
337 +`;
338 +
339 exports[`commit tree should be able to rebuild the store tree for each commit: 0: CommitTree 1`] = `
340 Object {
341 "nodes": Map {
packages/react-devtools-shared/src/__tests__/__snapshots__/store-test.js.snap
+58 -2
@@ -1,5 +1,63 @@
1 // Jest Snapshot v1, https://goo.gl/fbAQLP
2
3 +exports[`Store Lazy should support Lazy components (legacy render): 1: mounted + loading 1`] = `
4 +[root]
5 + ▾ <App>
6 + <Suspense>
7 +`;
8 +
9 +exports[`Store Lazy should support Lazy components (legacy render): 2: mounted + loaded 1`] = `
10 +[root]
11 + ▾ <App>
12 + ▾ <Suspense>
13 + <LazyInnerComponent>
14 +`;
15 +
16 +exports[`Store Lazy should support Lazy components (legacy render): 3: unmounted 1`] = `
17 +[root]
18 + <App>
19 +`;
20 +
21 +exports[`Store Lazy should support Lazy components in (createRoot): 1: mounted + loading 1`] = `
22 +[root]
23 + ▾ <App>
24 + <Suspense>
25 +`;
26 +
27 +exports[`Store Lazy should support Lazy components in (createRoot): 2: mounted + loaded 1`] = `
28 +[root]
29 + ▾ <App>
30 + ▾ <Suspense>
31 + <LazyInnerComponent>
32 +`;
33 +
34 +exports[`Store Lazy should support Lazy components in (createRoot): 3: unmounted 1`] = `
35 +[root]
36 + <App>
37 +`;
38 +
39 +exports[`Store Lazy should support Lazy components that are unmounted before they finish loading (legacy render): 1: mounted + loading 1`] = `
40 +[root]
41 + ▾ <App>
42 + <Suspense>
43 +`;
44 +
45 +exports[`Store Lazy should support Lazy components that are unmounted before they finish loading (legacy render): 2: unmounted 1`] = `
46 +[root]
47 + <App>
48 +`;
49 +
50 +exports[`Store Lazy should support Lazy components that are unmounted before they finish loading in (createRoot): 1: mounted + loading 1`] = `
51 +[root]
52 + ▾ <App>
53 + <Suspense>
54 +`;
55 +
56 +exports[`Store Lazy should support Lazy components that are unmounted before they finish loading in (createRoot): 2: unmounted 1`] = `
57 +[root]
58 + <App>
59 +`;
60 +
61 exports[`Store collapseNodesByDefault:false should display Suspense nodes properly in various states: 1: loading 1`] = `
62 [root]
63 ▾ <Wrapper>
@@ -624,8 +682,6 @@ exports[`Store should show the right display names for special component types 1
682 <MyComponent4> [Memo]
683 ▾ <MyComponent> [Memo]
684 <MyComponent> [ForwardRef]
627 - ▾ <Suspense>
628 - <MyComponent5>
685 <Baz> [withFoo][withBar]
686 <Baz> [Memo][withFoo][withBar]
687 <Baz> [ForwardRef][withFoo][withBar]
packages/react-devtools-shared/src/__tests__/profilingCommitTreeBuilder-test.js
+189
@@ -79,4 +79,193 @@ describe('commit tree', () => {
79 expect(renderFinished).toBe(true);
80 }
81 });
82 +
83 + describe('Lazy', () => {
84 + async function fakeImport(result) {
85 + return {default: result};
86 + }
87 +
88 + const LazyInnerComponent = () => null;
89 +
90 + const App = ({renderChildren}) => {
91 + if (renderChildren) {
92 + return (
93 + <React.Suspense fallback="Loading...">
94 + <LazyComponent />
95 + </React.Suspense>
96 + );
97 + } else {
98 + return null;
99 + }
100 + };
101 +
102 + let LazyComponent;
103 + beforeEach(() => {
104 + LazyComponent = React.lazy(() => fakeImport(LazyInnerComponent));
105 + });
106 +
107 + it('should support Lazy components (legacy render)', async done => {
108 + const container = document.createElement('div');
109 +
110 + utils.act(() => store.profilerStore.startProfiling());
111 + utils.act(() =>
112 + ReactDOM.render(<App renderChildren={true} />, container),
113 + );
114 + await Promise.resolve();
115 + utils.act(() =>
116 + ReactDOM.render(<App renderChildren={true} />, container),
117 + );
118 + utils.act(() =>
119 + ReactDOM.render(<App renderChildren={false} />, container),
120 + );
121 + utils.act(() => store.profilerStore.stopProfiling());
122 +
123 + let renderFinished = false;
124 +
125 + function Validator({commitIndex, rootID}) {
126 + const commitTree = store.profilerStore.profilingCache.getCommitTree({
127 + commitIndex,
128 + rootID,
129 + });
130 + expect(commitTree).toMatchSnapshot(`${commitIndex}: CommitTree`);
131 + renderFinished = true;
132 + return null;
133 + }
134 +
135 + const rootID = store.roots[0];
136 +
137 + for (let commitIndex = 0; commitIndex < 2; commitIndex++) {
138 + renderFinished = false;
139 +
140 + utils.act(() => {
141 + TestRenderer.create(
142 + <Validator commitIndex={commitIndex} rootID={rootID} />,
143 + );
144 + });
145 +
146 + expect(renderFinished).toBe(true);
147 + }
148 +
149 + done();
150 + });
151 +
152 + it('should support Lazy components (createRoot)', async done => {
153 + const container = document.createElement('div');
154 + const root = ReactDOM.unstable_createRoot(container);
155 +
156 + utils.act(() => store.profilerStore.startProfiling());
157 + utils.act(() => root.render(<App renderChildren={true} />));
158 + await Promise.resolve();
159 + utils.act(() => root.render(<App renderChildren={true} />));
160 + utils.act(() => root.render(<App renderChildren={false} />));
161 + utils.act(() => store.profilerStore.stopProfiling());
162 +
163 + let renderFinished = false;
164 +
165 + function Validator({commitIndex, rootID}) {
166 + const commitTree = store.profilerStore.profilingCache.getCommitTree({
167 + commitIndex,
168 + rootID,
169 + });
170 + expect(commitTree).toMatchSnapshot(`${commitIndex}: CommitTree`);
171 + renderFinished = true;
172 + return null;
173 + }
174 +
175 + const rootID = store.roots[0];
176 +
177 + for (let commitIndex = 0; commitIndex < 2; commitIndex++) {
178 + renderFinished = false;
179 +
180 + utils.act(() => {
181 + TestRenderer.create(
182 + <Validator commitIndex={commitIndex} rootID={rootID} />,
183 + );
184 + });
185 +
186 + expect(renderFinished).toBe(true);
187 + }
188 +
189 + done();
190 + });
191 +
192 + it('should support Lazy components that are unmounted before resolving (legacy render)', async done => {
193 + const container = document.createElement('div');
194 +
195 + utils.act(() => store.profilerStore.startProfiling());
196 + utils.act(() =>
197 + ReactDOM.render(<App renderChildren={true} />, container),
198 + );
199 + utils.act(() =>
200 + ReactDOM.render(<App renderChildren={false} />, container),
201 + );
202 + utils.act(() => store.profilerStore.stopProfiling());
203 +
204 + let renderFinished = false;
205 +
206 + function Validator({commitIndex, rootID}) {
207 + const commitTree = store.profilerStore.profilingCache.getCommitTree({
208 + commitIndex,
209 + rootID,
210 + });
211 + expect(commitTree).toMatchSnapshot(`${commitIndex}: CommitTree`);
212 + renderFinished = true;
213 + return null;
214 + }
215 +
216 + const rootID = store.roots[0];
217 +
218 + for (let commitIndex = 0; commitIndex < 2; commitIndex++) {
219 + renderFinished = false;
220 +
221 + utils.act(() => {
222 + TestRenderer.create(
223 + <Validator commitIndex={commitIndex} rootID={rootID} />,
224 + );
225 + });
226 +
227 + expect(renderFinished).toBe(true);
228 + }
229 +
230 + done();
231 + });
232 +
233 + it('should support Lazy components that are unmounted before resolving (createRoot)', async done => {
234 + const container = document.createElement('div');
235 + const root = ReactDOM.unstable_createRoot(container);
236 +
237 + utils.act(() => store.profilerStore.startProfiling());
238 + utils.act(() => root.render(<App renderChildren={true} />));
239 + utils.act(() => root.render(<App renderChildren={false} />));
240 + utils.act(() => store.profilerStore.stopProfiling());
241 +
242 + let renderFinished = false;
243 +
244 + function Validator({commitIndex, rootID}) {
245 + const commitTree = store.profilerStore.profilingCache.getCommitTree({
246 + commitIndex,
247 + rootID,
248 + });
249 + expect(commitTree).toMatchSnapshot(`${commitIndex}: CommitTree`);
250 + renderFinished = true;
251 + return null;
252 + }
253 +
254 + const rootID = store.roots[0];
255 +
256 + for (let commitIndex = 0; commitIndex < 2; commitIndex++) {
257 + renderFinished = false;
258 +
259 + utils.act(() => {
260 + TestRenderer.create(
261 + <Validator commitIndex={commitIndex} rootID={rootID} />,
262 + );
263 + });
264 +
265 + expect(renderFinished).toBe(true);
266 + }
267 +
268 + done();
269 + });
270 + });
271 });
packages/react-devtools-shared/src/__tests__/store-test.js
+105 -9
@@ -850,10 +850,6 @@ describe('Store', () => {
850 });
851
852 it('should show the right display names for special component types', async done => {
853 - async function fakeImport(result) {
854 - return {default: result};
855 - }
856 -
853 const MyComponent = (props, ref) => null;
854 const ForwardRefComponent = React.forwardRef(MyComponent);
855 const MyComponent2 = (props, ref) => null;
@@ -868,8 +864,6 @@ describe('Store', () => {
864 const MyComponent4 = (props, ref) => null;
865 const MemoComponent = React.memo(MyComponent4);
866 const MemoForwardRefComponent = React.memo(ForwardRefComponent);
871 - const MyComponent5 = (props, ref) => null;
872 - const LazyComponent = React.lazy(() => fakeImport(MyComponent5));
867
868 const FakeHigherOrderComponent = () => null;
869 FakeHigherOrderComponent.displayName = 'withFoo(withBar(Baz))';
@@ -889,9 +883,6 @@ describe('Store', () => {
883 <ForwardRefComponentWithCustomDisplayName />
884 <MemoComponent />
885 <MemoForwardRefComponent />
892 - <React.Suspense fallback="Loading...">
893 - <LazyComponent />
894 - </React.Suspense>
886 <FakeHigherOrderComponent />
887 <MemoizedFakeHigherOrderComponent />
888 <ForwardRefFakeHigherOrderComponent />
@@ -912,4 +903,109 @@ describe('Store', () => {
903
904 done();
905 });
906 +
907 + describe('Lazy', () => {
908 + async function fakeImport(result) {
909 + return {default: result};
910 + }
911 +
912 + const LazyInnerComponent = () => null;
913 +
914 + const App = ({renderChildren}) => {
915 + if (renderChildren) {
916 + return (
917 + <React.Suspense fallback="Loading...">
918 + <LazyComponent />
919 + </React.Suspense>
920 + );
921 + } else {
922 + return null;
923 + }
924 + };
925 +
926 + let LazyComponent;
927 + beforeEach(() => {
928 + LazyComponent = React.lazy(() => fakeImport(LazyInnerComponent));
929 + });
930 +
931 + it('should support Lazy components (legacy render)', async done => {
932 + const container = document.createElement('div');
933 +
934 + // Render once to start fetching the lazy component
935 + act(() => ReactDOM.render(<App renderChildren={true} />, container));
936 +
937 + expect(store).toMatchSnapshot('1: mounted + loading');
938 +
939 + await Promise.resolve();
940 +
941 + // Render again after it resolves
942 + act(() => ReactDOM.render(<App renderChildren={true} />, container));
943 +
944 + expect(store).toMatchSnapshot('2: mounted + loaded');
945 +
946 + // Render again to unmount it
947 + act(() => ReactDOM.render(<App renderChildren={false} />, container));
948 +
949 + expect(store).toMatchSnapshot('3: unmounted');
950 +
951 + done();
952 + });
953 +
954 + it('should support Lazy components in (createRoot)', async done => {
955 + const container = document.createElement('div');
956 + const root = ReactDOM.unstable_createRoot(container);
957 +
958 + // Render once to start fetching the lazy component
959 + act(() => root.render(<App renderChildren={true} />));
960 +
961 + expect(store).toMatchSnapshot('1: mounted + loading');
962 +
963 + await Promise.resolve();
964 +
965 + // Render again after it resolves
966 + act(() => root.render(<App renderChildren={true} />));
967 +
968 + expect(store).toMatchSnapshot('2: mounted + loaded');
969 +
970 + // Render again to unmount it
971 + act(() => root.render(<App renderChildren={false} />));
972 +
973 + expect(store).toMatchSnapshot('3: unmounted');
974 +
975 + done();
976 + });
977 +
978 + it('should support Lazy components that are unmounted before they finish loading (legacy render)', async done => {
979 + const container = document.createElement('div');
980 +
981 + // Render once to start fetching the lazy component
982 + act(() => ReactDOM.render(<App renderChildren={true} />, container));
983 +
984 + expect(store).toMatchSnapshot('1: mounted + loading');
985 +
986 + // Render again to unmount it before it finishes loading
987 + act(() => ReactDOM.render(<App renderChildren={false} />, container));
988 +
989 + expect(store).toMatchSnapshot('2: unmounted');
990 +
991 + done();
992 + });
993 +
994 + it('should support Lazy components that are unmounted before they finish loading in (createRoot)', async done => {
995 + const container = document.createElement('div');
996 + const root = ReactDOM.unstable_createRoot(container);
997 +
998 + // Render once to start fetching the lazy component
999 + act(() => root.render(<App renderChildren={true} />));
1000 +
1001 + expect(store).toMatchSnapshot('1: mounted + loading');
1002 +
1003 + // Render again to unmount it before it finishes loading
1004 + act(() => root.render(<App renderChildren={false} />));
1005 +
1006 + expect(store).toMatchSnapshot('2: unmounted');
1007 +
1008 + done();
1009 + });
1010 + });
1011 });
packages/react-devtools-shared/src/backend/renderer.js
+21 -10
@@ -545,7 +545,12 @@ export function attach(
545 }
546 }
547
548 - const debug = (name: string, fiber: Fiber, parentFiber: ?Fiber): void => {
548 + const debug = (
549 + name: string,
550 + fiber: Fiber,
551 + parentFiber: ?Fiber,
552 + extraString?: string = '',
553 + ): void => {
554 if (__DEBUG__) {
555 const displayName =
556 fiber.tag + ':' + (getDisplayNameForFiber(fiber) || 'null');
@@ -562,10 +567,11 @@ export function attach(
567 console.log(
568 `[renderer] %c${name} %c${displayName} (${id}) %c${
569 parentFiber ? `${parentDisplayName} (${parentID})` : ''
565 - }`,
570 + } %c${extraString}`,
571 'color: red; font-weight: bold;',
572 'color: blue;',
573 'color: purple;',
574 + 'color: black;',
575 );
576 }
577 };
@@ -1237,7 +1243,12 @@ export function attach(
1243
1244 function recordUnmount(fiber: Fiber, isSimulated: boolean) {
1245 if (__DEBUG__) {
1240 - debug('recordUnmount()', fiber);
1246 + debug(
1247 + 'recordUnmount()',
1248 + fiber,
1249 + null,
1250 + isSimulated ? 'unmount is simulated' : '',
1251 + );
1252 }
1253
1254 if (trackedPathMatchFiber !== null) {
@@ -1255,17 +1266,17 @@ export function attach(
1266 const isRoot = fiber.tag === HostRoot;
1267 const primaryFiber = getPrimaryFiber(fiber);
1268 if (!fiberToIDMap.has(primaryFiber)) {
1258 - // If we've never seen this Fiber, it might be because
1259 - // it is inside a non-current Suspense fragment tree,
1260 - // and so the store is not even aware of it.
1261 - // In that case we can just ignore it, or otherwise
1262 - // there will be errors later on.
1269 + // If we've never seen this Fiber, it might be inside of a legacy render Suspense fragment (so the store is not even aware of it).
1270 + // In that case we can just ignore it or it will cause errors later on.
1271 + // One example of this is a Lazy component that never resolves before being unmounted.
1272 + //
1273 + // TODO: This is fragile and can obscure actual bugs.
1274 + //
1275 + // Calling getPrimaryFiber() lazily adds fibers to the Map, so clean up after ourselves before returning.
1276 primaryFibers.delete(primaryFiber);
1264 - // TODO: this is fragile and can obscure actual bugs.
1277 return;
1278 }
1279 const id = getFiberID(primaryFiber);
1268 -
1280 if (isRoot) {
1281 // Roots must be removed only after all children (pending and simulated) have been removed.
1282 // So we track it separately.