Skip to content

Commit cc1a6cc

Browse files
committed
Inspect hooks lazily in case it might give us a better stack
1 parent d587434 commit cc1a6cc

File tree

1 file changed

+58
-31
lines changed
  • packages/react-devtools-shared/src/backend/fiber

1 file changed

+58
-31
lines changed

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

Lines changed: 58 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ import type {
1515
ReactIOInfo,
1616
} from 'shared/ReactTypes';
1717

18+
import type {HooksTree} from 'react-debug-tools/src/ReactDebugHooks';
19+
1820
import {
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

Comments
 (0)