Skip to content

Commit 62a634b

Browse files
authored
[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" />
1 parent 53d0794 commit 62a634b

File tree

1 file changed

+21
-1
lines changed

1 file changed

+21
-1
lines changed

packages/react-debug-tools/src/ReactDebugHooks.js

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,8 @@ function getPrimitiveStackCache(): Map<string, Array<any>> {
147147
let currentFiber: null | Fiber = null;
148148
let currentHook: null | Hook = null;
149149
let currentContextDependency: null | ContextDependency<mixed> = null;
150+
let currentThenableIndex: number = 0;
151+
let currentThenableState: null | Array<Thenable<mixed>> = null;
150152

151153
function nextHook(): null | Hook {
152154
const hook = currentHook;
@@ -201,7 +203,15 @@ function use<T>(usable: Usable<T>): T {
201203
if (usable !== null && typeof usable === 'object') {
202204
// $FlowFixMe[method-unbinding]
203205
if (typeof usable.then === 'function') {
204-
const thenable: Thenable<any> = (usable: any);
206+
const thenable: Thenable<any> =
207+
// If we have thenable state, then the actually used thenable will be the one
208+
// stashed in it. It's possible for uncached Promises to be new each render
209+
// and in that case the one we're inspecting is the in the thenable state.
210+
currentThenableState !== null &&
211+
currentThenableIndex < currentThenableState.length
212+
? currentThenableState[currentThenableIndex++]
213+
: (usable: any);
214+
205215
switch (thenable.status) {
206216
case 'fulfilled': {
207217
const fulfilledValue: T = thenable.value;
@@ -1285,6 +1295,14 @@ export function inspectHooksOfFiber(
12851295
// current state from them.
12861296
currentHook = (fiber.memoizedState: Hook);
12871297
currentFiber = fiber;
1298+
const thenableState =
1299+
fiber.dependencies && fiber.dependencies._debugThenableState;
1300+
// In DEV the thenableState is an inner object.
1301+
const usedThenables: any = thenableState
1302+
? thenableState.thenables || thenableState
1303+
: null;
1304+
currentThenableState = Array.isArray(usedThenables) ? usedThenables : null;
1305+
currentThenableIndex = 0;
12881306

12891307
if (hasOwnProperty.call(currentFiber, 'dependencies')) {
12901308
// $FlowFixMe[incompatible-use]: Flow thinks hasOwnProperty might have nulled `currentFiber`
@@ -1339,6 +1357,8 @@ export function inspectHooksOfFiber(
13391357
currentFiber = null;
13401358
currentHook = null;
13411359
currentContextDependency = null;
1360+
currentThenableState = null;
1361+
currentThenableIndex = 0;
13421362

13431363
restoreContexts(contextMap);
13441364
}

0 commit comments

Comments
 (0)