Repository: facebook/react
Pull request: [Fiber] Stash ThenableState on the Dependencies Object for Use By DevTools

This lets us track what a Component might suspend on from DevTools. We could already collect this by replaying a component's Hooks but that would be expensive to collect from a whole tree.

The thenables themselves might contain useful information but mainly we'd want access to the `_debugInfo` on the thenables which might contain additional information from the server. 

https://github.com/facebook/react/blob/19bd26beb689e554fceb0b929dc5199be8cba594/packages/shared/ReactTypes.js#L114

In a follow up we should really do something similar in Flight to transfer `use()` on the debugInfo of that Server Component.

Changed files:
filename: packages/react-reconciler/src/ReactFiber.js
patch: @@ -404,10 +404,16 @@ export function createWorkInProgress(current: Fiber, pendingProps: any): Fiber {
   workInProgress.dependencies =
     currentDependencies === null
       ? null
-      : {
-          lanes: currentDependencies.lanes,
-          firstContext: currentDependencies.firstContext,
-        };
+      : __DEV__
+        ? {
+            lanes: currentDependencies.lanes,
+            firstContext: currentDependencies.firstContext,
+            _debugThenableState: currentDependencies._debugThenableState,
+          }
+        : {
+            lanes: currentDependencies.lanes,
+            firstContext: currentDependencies.firstContext,
+          };
 
   // These will be overridden during the parent's reconciliation
   workInProgress.sibling = current.sibling;
@@ -503,10 +509,16 @@ export function resetWorkInProgress(
     workInProgress.dependencies =
       currentDependencies === null
         ? null
-        : {
-            lanes: currentDependencies.lanes,
-            firstContext: currentDependencies.firstContext,
-          };
+        : __DEV__
+          ? {
+              lanes: currentDependencies.lanes,
+              firstContext: currentDependencies.firstContext,
+              _debugThenableState: currentDependencies._debugThenableState,
+            }
+          : {
+              lanes: currentDependencies.lanes,
+              firstContext: currentDependencies.firstContext,
+            };
 
     if (enableProfilerTimer) {
       // Note: We don't reset the actualTime counts. It's useful to accumulate

filename: packages/react-reconciler/src/ReactFiberHooks.js
patch: @@ -637,6 +637,18 @@ function finishRenderingHooks<Props, SecondArg>(
 ): void {
   if (__DEV__) {
     workInProgress._debugHookTypes = hookTypesDev;
+    // Stash the thenable state for use by DevTools.
+    if (workInProgress.dependencies === null) {
+      if (thenableState !== null) {
+        workInProgress.dependencies = {
+          lanes: NoLanes,
+          firstContext: null,
+          _debugThenableState: thenableState,
+        };
+      }
+    } else {
+      workInProgress.dependencies._debugThenableState = thenableState;
+    }
   }
 
   // We can assume the previous dispatcher is always this one, since we set it

filename: packages/react-reconciler/src/ReactFiberNewContext.js
patch: @@ -825,10 +825,16 @@ function readContextForConsumer_withSelect<C>(
 
       // This is the first dependency for this component. Create a new list.
       lastContextDependency = contextItem;
-      consumer.dependencies = {
-        lanes: NoLanes,
-        firstContext: contextItem,
-      };
+      consumer.dependencies = __DEV__
+        ? {
+            lanes: NoLanes,
+            firstContext: contextItem,
+            _debugThenableState: null,
+          }
+        : {
+            lanes: NoLanes,
+            firstContext: contextItem,
+          };
       if (enableLazyContextPropagation) {
         consumer.flags |= NeedsPropagation;
       }
@@ -869,10 +875,16 @@ function readContextForConsumer<C>(
 
       // This is the first dependency for this component. Create a new list.
       lastContextDependency = contextItem;
-      consumer.dependencies = {
-        lanes: NoLanes,
-        firstContext: contextItem,
-      };
+      consumer.dependencies = __DEV__
+        ? {
+            lanes: NoLanes,
+            firstContext: contextItem,
+            _debugThenableState: null,
+          }
+        : {
+            lanes: NoLanes,
+            firstContext: contextItem,
+          };
       if (enableLazyContextPropagation) {
         consumer.flags |= NeedsPropagation;
       }

filename: packages/react-reconciler/src/ReactInternalTypes.js
patch: @@ -37,6 +37,7 @@ import type {
 } from './ReactFiberTracingMarkerComponent';
 import type {ConcurrentUpdate} from './ReactFiberConcurrentUpdates';
 import type {ComponentStackNode} from 'react-server/src/ReactFizzComponentStack';
+import type {ThenableState} from './ReactFiberThenable';
 
 // Unwind Circular: moved from ReactFiberHooks.old
 export type HookType =
@@ -81,7 +82,7 @@ export type Dependencies = {
     | ContextDependency<mixed>
     | ContextDependencyWithSelect<mixed>
     | null,
-  ...
+  _debugThenableState?: null | ThenableState, // DEV-only
 };
 
 export type MemoCache = {