From 34ce3acafdcfb6830250043b64d8af2450c730bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Markb=C3=A5ge?= Date: Mon, 11 Aug 2025 11:42:59 -0400 Subject: [PATCH] [DevTools] Pick up suspended by info from React.lazy in type position (#34144) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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. Screenshot 2025-08-08 at 11 32 33 PM --- .../src/backend/fiber/renderer.js | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/packages/react-devtools-shared/src/backend/fiber/renderer.js b/packages/react-devtools-shared/src/backend/fiber/renderer.js index 3a3c254f5c..6fb5a66c7d 100644 --- a/packages/react-devtools-shared/src/backend/fiber/renderer.js +++ b/packages/react-devtools-shared/src/backend/fiber/renderer.js @@ -104,6 +104,7 @@ import { MEMO_NUMBER, MEMO_SYMBOL_STRING, SERVER_CONTEXT_SYMBOL_STRING, + LAZY_SYMBOL_STRING, } from '../shared/ReactSymbols'; import {enableStyleXFeatures} from 'react-devtools-feature-flags'; @@ -3161,6 +3162,25 @@ export function attach( return null; } + function trackDebugInfoFromLazyType(fiber: Fiber): void { + // The debugInfo from a Lazy isn't propagated onto _debugInfo of the parent Fiber the way + // it is when used in child position. So we need to pick it up explicitly. + const type = fiber.elementType; + const typeSymbol = getTypeSymbol(type); // The elementType might be have been a LazyComponent. + if (typeSymbol === LAZY_SYMBOL_STRING) { + const debugInfo: ?ReactDebugInfo = type._debugInfo; + if (debugInfo) { + for (let i = 0; i < debugInfo.length; i++) { + const debugEntry = debugInfo[i]; + if (debugEntry.awaited) { + const asyncInfo: ReactAsyncInfo = (debugEntry: any); + insertSuspendedBy(asyncInfo); + } + } + } + } + } + function mountVirtualChildrenRecursively( firstChild: Fiber, lastChild: null | Fiber, // non-inclusive @@ -3379,6 +3399,8 @@ export function attach( // because we don't want to highlight every host node inside of a newly mounted subtree. } + trackDebugInfoFromLazyType(fiber); + if (fiber.tag === HostHoistable) { const nearestInstance = reconcilingParent; if (nearestInstance === null) { @@ -4208,6 +4230,8 @@ export function attach( } } try { + trackDebugInfoFromLazyType(nextFiber); + if ( nextFiber.tag === HostHoistable && prevFiber.memoizedState !== nextFiber.memoizedState