@@ -15,6 +15,8 @@ import type {
1515 ReactIOInfo ,
1616} from 'shared/ReactTypes' ;
1717
18+ import type { HooksTree } from 'react-debug-tools/src/ReactDebugHooks' ;
19+
1820import {
1921 ComponentFilterDisplayName ,
2022 ComponentFilterElementType ,
@@ -5187,6 +5189,32 @@ export function attach(
51875189 return null;
51885190 }
51895191
5192+ function inspectHooks(fiber: Fiber): HooksTree {
5193+ const originalConsoleMethods: {[string]: $FlowFixMe} = {};
5194+
5195+ // Temporarily disable all console logging before re-running the hook.
5196+ for (const method in console) {
5197+ try {
5198+ // $FlowFixMe[invalid-computed-prop]
5199+ originalConsoleMethods[method] = console[method];
5200+ // $FlowFixMe[prop-missing]
5201+ console[method] = () => {};
5202+ } catch (error) {}
5203+ }
5204+
5205+ try {
5206+ return inspectHooksOfFiber(fiber, getDispatcherRef(renderer));
5207+ } finally {
5208+ // Restore original console functionality.
5209+ for (const method in originalConsoleMethods) {
5210+ try {
5211+ // $FlowFixMe[prop-missing]
5212+ console[method] = originalConsoleMethods[method];
5213+ } catch (error) {}
5214+ }
5215+ }
5216+ }
5217+
51905218 function getSuspendedByOfSuspenseNode(
51915219 suspenseNode: SuspenseNode,
51925220 ): Array<SerializedAsyncInfo> {
@@ -5196,6 +5224,11 @@ export function attach(
51965224 if (!suspenseNode.hasUniqueSuspenders) {
51975225 return result;
51985226 }
5227+ // Cache the inspection of Hooks in case we need it for multiple entries.
5228+ // We don't need a full map here since it's likely that every ioInfo that's unique
5229+ // to a specific instance will have those appear in order of when that instance was discovered.
5230+ let hooksCacheKey: null | DevToolsInstance = null;
5231+ let hooksCache: null | HooksTree = null;
51995232 suspenseNode.suspendedBy.forEach((set, ioInfo) => {
52005233 let parentNode = suspenseNode.parent;
52015234 while (parentNode !== null) {
@@ -5217,8 +5250,24 @@ export function attach(
52175250 ioInfo,
52185251 );
52195252 if (asyncInfo !== null) {
5220- const index = result.length;
5221- result.push(serializeAsyncInfo(asyncInfo, index, firstInstance));
5253+ let hooks: null | HooksTree = null;
5254+ if (asyncInfo.stack == null && asyncInfo.owner == null) {
5255+ if (hooksCacheKey === firstInstance) {
5256+ hooks = hooksCache;
5257+ } else if (firstInstance.kind !== VIRTUAL_INSTANCE) {
5258+ const fiber = firstInstance.data;
5259+ if (
5260+ fiber.dependencies &&
5261+ fiber.dependencies._debugThenableState
5262+ ) {
5263+ // This entry had no stack nor owner but this Fiber used Hooks so we might
5264+ // be able to get the stack from the Hook.
5265+ hooksCacheKey = firstInstance;
5266+ hooksCache = hooks = inspectHooks(fiber);
5267+ }
5268+ }
5269+ }
5270+ result.push(serializeAsyncInfo(asyncInfo, firstInstance, hooks));
52225271 }
52235272 }
52245273 });
@@ -5227,8 +5276,8 @@ export function attach(
52275276
52285277 function serializeAsyncInfo(
52295278 asyncInfo: ReactAsyncInfo,
5230- index: number,
52315279 parentInstance: DevToolsInstance,
5280+ hooks: null | HooksTree,
52325281 ): SerializedAsyncInfo {
52335282 const ioInfo = asyncInfo.awaited;
52345283 const ioOwnerInstance = findNearestOwnerInstance(
@@ -5538,31 +5587,9 @@ export function attach(
55385587 const owners: null | Array<SerializedElement> =
55395588 getOwnersListFromInstance(fiberInstance);
55405589
5541- let hooks = null;
5590+ let hooks: null | HooksTree = null;
55425591 if (usesHooks) {
5543- const originalConsoleMethods: {[string]: $FlowFixMe} = {};
5544-
5545- // Temporarily disable all console logging before re-running the hook.
5546- for (const method in console) {
5547- try {
5548- // $FlowFixMe[invalid-computed-prop]
5549- originalConsoleMethods[method] = console[method];
5550- // $FlowFixMe[prop-missing]
5551- console[method] = () => {};
5552- } catch (error) {}
5553- }
5554-
5555- try {
5556- hooks = inspectHooksOfFiber(fiber, getDispatcherRef(renderer));
5557- } finally {
5558- // Restore original console functionality.
5559- for (const method in originalConsoleMethods) {
5560- try {
5561- // $FlowFixMe[prop-missing]
5562- console[method] = originalConsoleMethods[method];
5563- } catch (error) {}
5564- }
5565- }
5592+ hooks = inspectHooks(fiber);
55665593 }
55675594
55685595 let rootType = null;
@@ -5641,8 +5668,8 @@ export function attach(
56415668 // TODO: Prepend other suspense sources like css, images and use().
56425669 fiberInstance.suspendedBy === null
56435670 ? []
5644- : fiberInstance.suspendedBy.map(( info, index) =>
5645- serializeAsyncInfo(info, index, fiberInstance ),
5671+ : fiberInstance.suspendedBy.map(info =>
5672+ serializeAsyncInfo(info, fiberInstance, hooks ),
56465673 );
56475674 return {
56485675 id: fiberInstance.id,
@@ -5813,8 +5840,8 @@ export function attach(
58135840 suspendedBy:
58145841 suspendedBy === null
58155842 ? []
5816- : suspendedBy.map(( info, index) =>
5817- serializeAsyncInfo(info, index, virtualInstance ),
5843+ : suspendedBy.map(info =>
5844+ serializeAsyncInfo(info, virtualInstance, null ),
58185845 ),
58195846
58205847 // List of owners
0 commit comments