[DevTools] Pick up suspended by info from React.lazy in type position (#34144)
Normally, we pick up debug info from instrumented Promise or React.Lazy while we're reconciling in ReactChildFiber when they appear in the child position. We add those to the `_debugInfo` of the Fiber. However, we don't do that for for Lazy in the Component type position. Instead, we have to pick up the debug info from it explicitly in DevTools. Likely this is the info added by #34137. Older versions wouldn't be covered by this particular mechanism but more generally from throwing a Promise. <img width="592" height="449" alt="Screenshot 2025-08-08 at 11 32 33 PM" src="https://github.com/user-attachments/assets/87211c64-a7df-47b7-a784-5cdc7c5fae16" />
Sebastian Markbåge committed
Aug 11, 2025 at 11:42 UTC
34ce3acafdcfb6830250043b64d8af2450c730bc
1 file changed
+24
packages/react-devtools-shared/src/backend/fiber/renderer.js
+24
@@ -104,6 +104,7 @@ import {
104
MEMO_NUMBER,
105
MEMO_SYMBOL_STRING,
106
SERVER_CONTEXT_SYMBOL_STRING,
107
+ LAZY_SYMBOL_STRING,
108
} from '../shared/ReactSymbols';
109
import {enableStyleXFeatures} from 'react-devtools-feature-flags';
110
@@ -3161,6 +3162,25 @@ export function attach(
3162
return null;
3163
}
3164
3165
+ function trackDebugInfoFromLazyType(fiber: Fiber): void {
3166
+ // The debugInfo from a Lazy isn't propagated onto _debugInfo of the parent Fiber the way
3167
+ // it is when used in child position. So we need to pick it up explicitly.
3168
+ const type = fiber.elementType;
3169
+ const typeSymbol = getTypeSymbol(type); // The elementType might be have been a LazyComponent.
3170
+ if (typeSymbol === LAZY_SYMBOL_STRING) {
3171
+ const debugInfo: ?ReactDebugInfo = type._debugInfo;
3172
+ if (debugInfo) {
3173
+ for (let i = 0; i < debugInfo.length; i++) {
3174
+ const debugEntry = debugInfo[i];
3175
+ if (debugEntry.awaited) {
3176
+ const asyncInfo: ReactAsyncInfo = (debugEntry: any);
3177
+ insertSuspendedBy(asyncInfo);
3178
+ }
3179
+ }
3180
+ }
3181
+ }
3182
+ }
3183
+
3184
function mountVirtualChildrenRecursively(
3185
firstChild: Fiber,
3186
lastChild: null | Fiber, // non-inclusive
@@ -3379,6 +3399,8 @@ export function attach(
3399
// because we don't want to highlight every host node inside of a newly mounted subtree.
3400
}
3401
3402
+ trackDebugInfoFromLazyType(fiber);
3403
+
3404
if (fiber.tag === HostHoistable) {
3405
const nearestInstance = reconcilingParent;
3406
if (nearestInstance === null) {
@@ -4208,6 +4230,8 @@ export function attach(
4230
}
4231
}
4232
try {
4233
+ trackDebugInfoFromLazyType(nextFiber);
4234
+
4235
if (
4236
nextFiber.tag === HostHoistable &&
4237
prevFiber.memoizedState !== nextFiber.memoizedState