Skip to content

Commit d587434

Browse files
authored
[DevTools] Pick up suspended by info from use() (#34148)
Similar to #34144 but for `use()`. `use()` dependencies don't get added to the `fiber._debugInfo` set because that just models the things blocking the children, and not the Fiber component itself. This picks up any debug info from the thenable state that we stashed onto `_debugThenableState` so that we know it used `use()`. <img width="593" height="425" alt="Screenshot 2025-08-09 at 4 03 40 PM" src="https://github.com/user-attachments/assets/c7e06884-4efd-47fa-a76b-132935db6ddc" /> Without #34146 this doesn't pick up uninstrumented promises but after it, it'll pick those up as well. An instrumented promise that doesn't have anything in its debug info is not picked up. For example, if it didn't depend on any I/O on the server. This doesn't yet pick up the stack trace of the `use()` call. That information is in the Hooks information but needs a follow up to extract it.
1 parent ca292f7 commit d587434

File tree

2 files changed

+37
-1
lines changed

2 files changed

+37
-1
lines changed

packages/react-devtools-shared/src/__tests__/inspectedElement-test.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -791,7 +791,7 @@ describe('InspectedElement', () => {
791791
"react_lazy": {
792792
"_payload": Dehydrated {
793793
"preview_short": {…},
794-
"preview_long": {_result: () => {}, _status: -1},
794+
"preview_long": {_ioInfo: {…}, _result: () => {}, _status: -1},
795795
},
796796
},
797797
"regexp": Dehydrated {

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

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
*/
99

1010
import type {
11+
Thenable,
1112
ReactComponentInfo,
1213
ReactDebugInfo,
1314
ReactAsyncInfo,
@@ -3181,6 +3182,39 @@ export function attach(
31813182
}
31823183
}
31833184
3185+
function trackDebugInfoFromUsedThenables(fiber: Fiber): void {
3186+
// If a Fiber called use() in DEV mode then we may have collected _debugThenableState on
3187+
// the dependencies. If so, then this will contain the thenables passed to use().
3188+
// These won't have their debug info picked up by fiber._debugInfo since that just
3189+
// contains things suspending the children. We have to collect use() separately.
3190+
const dependencies = fiber.dependencies;
3191+
if (dependencies == null) {
3192+
return;
3193+
}
3194+
const thenableState = dependencies._debugThenableState;
3195+
if (thenableState == null) {
3196+
return;
3197+
}
3198+
// In DEV the thenableState is an inner object.
3199+
const usedThenables: any = thenableState.thenables || thenableState;
3200+
if (!Array.isArray(usedThenables)) {
3201+
return;
3202+
}
3203+
for (let i = 0; i < usedThenables.length; i++) {
3204+
const thenable: Thenable<mixed> = usedThenables[i];
3205+
const debugInfo = thenable._debugInfo;
3206+
if (debugInfo) {
3207+
for (let j = 0; j < debugInfo.length; j++) {
3208+
const debugEntry = debugInfo[i];
3209+
if (debugEntry.awaited) {
3210+
const asyncInfo: ReactAsyncInfo = (debugEntry: any);
3211+
insertSuspendedBy(asyncInfo);
3212+
}
3213+
}
3214+
}
3215+
}
3216+
}
3217+
31843218
function mountVirtualChildrenRecursively(
31853219
firstChild: Fiber,
31863220
lastChild: null | Fiber, // non-inclusive
@@ -3400,6 +3434,7 @@ export function attach(
34003434
}
34013435
34023436
trackDebugInfoFromLazyType(fiber);
3437+
trackDebugInfoFromUsedThenables(fiber);
34033438
34043439
if (fiber.tag === HostHoistable) {
34053440
const nearestInstance = reconcilingParent;
@@ -4231,6 +4266,7 @@ export function attach(
42314266
}
42324267
try {
42334268
trackDebugInfoFromLazyType(nextFiber);
4269+
trackDebugInfoFromUsedThenables(nextFiber);
42344270
42354271
if (
42364272
nextFiber.tag === HostHoistable &&

0 commit comments

Comments
 (0)