Skip to content

Commit bd50e9c

Browse files
committed
Extract the stack from Hooks if we can find one that used this entry
1 parent cc1a6cc commit bd50e9c

File tree

1 file changed

+73
-0
lines changed
  • packages/react-devtools-shared/src/backend/fiber

1 file changed

+73
-0
lines changed

packages/react-devtools-shared/src/backend/fiber/renderer.js

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ import type {
1313
ReactDebugInfo,
1414
ReactAsyncInfo,
1515
ReactIOInfo,
16+
ReactStackTrace,
17+
ReactCallSite,
1618
} from 'shared/ReactTypes';
1719

1820
import type {HooksTree} from 'react-debug-tools/src/ReactDebugHooks';
@@ -5274,6 +5276,72 @@ export function attach(
52745276
return result;
52755277
}
52765278
5279+
function getAwaitStackFromHooks(
5280+
hooks: HooksTree,
5281+
asyncInfo: ReactAsyncInfo,
5282+
): null | ReactStackTrace {
5283+
// TODO: We search through the hooks tree generated by inspectHooksOfFiber so that we can
5284+
// use the information already extracted but ideally this search would be faster since we
5285+
// could know which index to extract from the debug state.
5286+
for (let i = 0; i < hooks.length; i++) {
5287+
const node = hooks[i];
5288+
const debugInfo = node.debugInfo;
5289+
if (debugInfo != null && debugInfo.indexOf(asyncInfo) !== -1) {
5290+
// Found a matching Hook. We'll now use its source location to construct a stack.
5291+
const source = node.hookSource;
5292+
if (
5293+
source != null &&
5294+
source.functionName !== null &&
5295+
source.fileName !== null &&
5296+
source.lineNumber !== null &&
5297+
source.columnNumber !== null
5298+
) {
5299+
// Unfortunately this is in a slightly different format. TODO: Unify HookNode with ReactCallSite.
5300+
const callSite: ReactCallSite = [
5301+
source.functionName,
5302+
source.fileName,
5303+
source.lineNumber,
5304+
source.columnNumber,
5305+
0,
5306+
0,
5307+
false,
5308+
];
5309+
// As we return we'll add any custom hooks parent stacks to the array.
5310+
return [callSite];
5311+
} else {
5312+
return [];
5313+
}
5314+
}
5315+
// Otherwise, search the sub hooks of any custom hook.
5316+
const matchedStack = getAwaitStackFromHooks(node.subHooks, asyncInfo);
5317+
if (matchedStack !== null) {
5318+
// Append this custom hook to the stack trace since it must have been called inside of it.
5319+
const source = node.hookSource;
5320+
if (
5321+
source != null &&
5322+
source.functionName !== null &&
5323+
source.fileName !== null &&
5324+
source.lineNumber !== null &&
5325+
source.columnNumber !== null
5326+
) {
5327+
// Unfortunately this is in a slightly different format. TODO: Unify HookNode with ReactCallSite.
5328+
const callSite: ReactCallSite = [
5329+
source.functionName,
5330+
source.fileName,
5331+
source.lineNumber,
5332+
source.columnNumber,
5333+
0,
5334+
0,
5335+
false,
5336+
];
5337+
matchedStack.push(callSite);
5338+
}
5339+
return matchedStack;
5340+
}
5341+
}
5342+
return null;
5343+
}
5344+
52775345
function serializeAsyncInfo(
52785346
asyncInfo: ReactAsyncInfo,
52795347
parentInstance: DevToolsInstance,
@@ -5317,6 +5385,11 @@ export function attach(
53175385
// If we awaited in the child position of a component, then the best stack would be the
53185386
// return callsite but we don't have that available so instead we skip. The callsite of
53195387
// the JSX would be misleading in this case. The same thing happens with throw-a-Promise.
5388+
if (hooks !== null) {
5389+
// If this component used Hooks we might be able to instead infer the stack from the
5390+
// use() callsite if this async info came from a hook. Let's search the tree to find it.
5391+
awaitStack = getAwaitStackFromHooks(hooks, asyncInfo);
5392+
}
53205393
break;
53215394
default:
53225395
// If we awaited by passing a Promise to a built-in element, then the JSX callsite is a

0 commit comments

Comments
 (0)