From 3aae2c22299f95a140c5dcbbe2344ca5b0785603 Mon Sep 17 00:00:00 2001 From: Sebastian Markbage Date: Sun, 10 Aug 2025 20:10:31 -0400 Subject: [PATCH] Use thenables from the _debugThenableState if available In the case where a Promise is not cached, then the thenable state might contain an older version. This version is the one that was actually observed by the committed render, so that's the version we'll want to inspect. --- .../react-debug-tools/src/ReactDebugHooks.js | 22 ++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/packages/react-debug-tools/src/ReactDebugHooks.js b/packages/react-debug-tools/src/ReactDebugHooks.js index 8242b27d4e5..54a6dd3e43a 100644 --- a/packages/react-debug-tools/src/ReactDebugHooks.js +++ b/packages/react-debug-tools/src/ReactDebugHooks.js @@ -147,6 +147,8 @@ function getPrimitiveStackCache(): Map> { let currentFiber: null | Fiber = null; let currentHook: null | Hook = null; let currentContextDependency: null | ContextDependency = null; +let currentThenableIndex: number = 0; +let currentThenableState: null | Array> = null; function nextHook(): null | Hook { const hook = currentHook; @@ -201,7 +203,15 @@ function use(usable: Usable): T { if (usable !== null && typeof usable === 'object') { // $FlowFixMe[method-unbinding] if (typeof usable.then === 'function') { - const thenable: Thenable = (usable: any); + const thenable: Thenable = + // If we have thenable state, then the actually used thenable will be the one + // stashed in it. It's possible for uncached Promises to be new each render + // and in that case the one we're inspecting is the in the thenable state. + currentThenableState !== null && + currentThenableIndex < currentThenableState.length + ? currentThenableState[currentThenableIndex++] + : (usable: any); + switch (thenable.status) { case 'fulfilled': { const fulfilledValue: T = thenable.value; @@ -1285,6 +1295,14 @@ export function inspectHooksOfFiber( // current state from them. currentHook = (fiber.memoizedState: Hook); currentFiber = fiber; + const thenableState = + fiber.dependencies && fiber.dependencies._debugThenableState; + // In DEV the thenableState is an inner object. + const usedThenables: any = thenableState + ? thenableState.thenables || thenableState + : null; + currentThenableState = Array.isArray(usedThenables) ? usedThenables : null; + currentThenableIndex = 0; if (hasOwnProperty.call(currentFiber, 'dependencies')) { // $FlowFixMe[incompatible-use]: Flow thinks hasOwnProperty might have nulled `currentFiber` @@ -1339,6 +1357,8 @@ export function inspectHooksOfFiber( currentFiber = null; currentHook = null; currentContextDependency = null; + currentThenableState = null; + currentThenableIndex = 0; restoreContexts(contextMap); }