[DebugTools] Use thenables from the _debugThenableState if available (#34161)

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.

We used to not store the thenable state but now we have it on
`_debugThenableState` in DEV.

<img width="593" height="359" alt="Screenshot 2025-08-10 at 8 26 04 PM"
src="https://github.com/user-attachments/assets/51ee53f3-a31a-4e3f-a4cf-bb20b6efe0cb"
/>
This commit is contained in:
Sebastian Markbåge 2025-08-11 11:46:27 -04:00 committed by GitHub
parent 53d07944df
commit 62a634b972
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -147,6 +147,8 @@ function getPrimitiveStackCache(): Map<string, Array<any>> {
let currentFiber: null | Fiber = null;
let currentHook: null | Hook = null;
let currentContextDependency: null | ContextDependency<mixed> = null;
let currentThenableIndex: number = 0;
let currentThenableState: null | Array<Thenable<mixed>> = null;
function nextHook(): null | Hook {
const hook = currentHook;
@ -201,7 +203,15 @@ function use<T>(usable: Usable<T>): T {
if (usable !== null && typeof usable === 'object') {
// $FlowFixMe[method-unbinding]
if (typeof usable.then === 'function') {
const thenable: Thenable<any> = (usable: any);
const thenable: Thenable<any> =
// 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);
}