@samitouri / QOS-React-2 / commits / fbc6386369

Fix DevTools handling of empty Suspense tag for legacy renderer versions (#19337)

Brian Vaughn committed Jul 13, 2020 at 16:21 UTC fbc63863692d291b50e55400673845f7c81aff61
4 files changed +90 -3
packages/react-devtools-shared/src/__tests__/__snapshots__/profilingCache-test.js.snap
+59
@@ -2191,6 +2191,65 @@ Object {
2191 }
2192 `;
2193
2194 +exports[`ProfilingCache should handle unexpectedly shallow suspense trees: Empty Suspense node 1`] = `
2195 +Object {
2196 + "commitData": Array [
2197 + Object {
2198 + "changeDescriptions": Map {},
2199 + "duration": 0,
2200 + "fiberActualDurations": Map {
2201 + 1 => 0,
2202 + 2 => 0,
2203 + },
2204 + "fiberSelfDurations": Map {
2205 + 1 => 0,
2206 + 2 => 0,
2207 + },
2208 + "interactionIDs": Array [],
2209 + "priorityLevel": "Normal",
2210 + "timestamp": 0,
2211 + },
2212 + ],
2213 + "displayName": "Suspense",
2214 + "initialTreeBaseDurations": Map {},
2215 + "interactionCommits": Map {},
2216 + "interactions": Map {},
2217 + "operations": Array [
2218 + Array [
2219 + 1,
2220 + 1,
2221 + 9,
2222 + 8,
2223 + 83,
2224 + 117,
2225 + 115,
2226 + 112,
2227 + 101,
2228 + 110,
2229 + 115,
2230 + 101,
2231 + 1,
2232 + 1,
2233 + 11,
2234 + 1,
2235 + 1,
2236 + 1,
2237 + 2,
2238 + 12,
2239 + 1,
2240 + 0,
2241 + 1,
2242 + 0,
2243 + 4,
2244 + 2,
2245 + 0,
2246 + ],
2247 + ],
2248 + "rootID": 1,
2249 + "snapshots": Map {},
2250 +}
2251 +`;
2252 +
2253 exports[`ProfilingCache should properly detect changed hooks: CommitDetails commitIndex: 0 1`] = `
2254 Object {
2255 "changeDescriptions": Map {
packages/react-devtools-shared/src/__tests__/profilingCache-test.js
+20
@@ -696,4 +696,24 @@ describe('ProfilingCache', () => {
696 ),
697 );
698 });
699 +
700 + it('should handle unexpectedly shallow suspense trees', () => {
701 + const container = document.createElement('div');
702 +
703 + utils.act(() => store.profilerStore.startProfiling());
704 + utils.act(() => ReactDOM.render(<React.Suspense />, container));
705 + utils.act(() => store.profilerStore.stopProfiling());
706 +
707 + function Validator({commitIndex, rootID}) {
708 + const profilingDataForRoot = store.profilerStore.getDataForRoot(rootID);
709 + expect(profilingDataForRoot).toMatchSnapshot('Empty Suspense node');
710 + return null;
711 + }
712 +
713 + const rootID = store.roots[0];
714 +
715 + utils.act(() => {
716 + TestRenderer.create(<Validator commitIndex={0} rootID={rootID} />);
717 + });
718 + });
719 });
packages/react-devtools-shared/src/backend/renderer.js
+6 -3
@@ -1237,11 +1237,14 @@ export function attach(
1237 );
1238 }
1239 } else {
1240 + let primaryChild: Fiber | null = null;
1241 const areSuspenseChildrenConditionallyWrapped =
1242 OffscreenComponent === -1;
1242 - const primaryChild: Fiber | null = areSuspenseChildrenConditionallyWrapped
1243 - ? fiber.child
1244 - : (fiber.child: any).child;
1243 + if (areSuspenseChildrenConditionallyWrapped) {
1244 + primaryChild = fiber.child;
1245 + } else if (fiber.child !== null) {
1246 + primaryChild = fiber.child.child;
1247 + }
1248 if (primaryChild !== null) {
1249 mountFiberRecursively(
1250 primaryChild,
packages/react-devtools-shell/src/app/SuspenseTree/index.js
+5
@@ -25,10 +25,15 @@ function SuspenseTree() {
25 <PrimaryFallbackTest initialSuspend={true} />
26 <NestedSuspenseTest />
27 <SuspenseListTest />
28 + <EmptySuspense />
29 </Fragment>
30 );
31 }
32
33 +function EmptySuspense() {
34 + return <Suspense />;
35 +}
36 +
37 function PrimaryFallbackTest({initialSuspend}) {
38 const [suspend, setSuspend] = useState(initialSuspend);
39 const fallbackStep = useTestSequence('fallback', Fallback1, Fallback2);