From aed00dacfb79d17c53218404c52b1c7aa59c4a89 Mon Sep 17 00:00:00 2001 From: Sebastian Silbermann Date: Sat, 24 Feb 2024 11:54:26 +0100 Subject: [PATCH] devtools: Use context displayName for context hook name (#25954) --- .../react-debug-tools/src/ReactDebugHooks.js | 26 +++++++++++++++++-- .../ReactHooksInspectionIntegration-test.js | 17 ++++++++++++ 2 files changed, 41 insertions(+), 2 deletions(-) diff --git a/packages/react-debug-tools/src/ReactDebugHooks.js b/packages/react-debug-tools/src/ReactDebugHooks.js index 1b285b562e19c..487aebe630271 100644 --- a/packages/react-debug-tools/src/ReactDebugHooks.js +++ b/packages/react-debug-tools/src/ReactDebugHooks.js @@ -39,6 +39,7 @@ type CurrentDispatcherRef = typeof ReactSharedInternals.ReactCurrentDispatcher; // Used to track hooks called during a render type HookLogEntry = { + displayName: string | null, primitive: string, stackError: Error, value: mixed, @@ -171,6 +172,7 @@ function use(usable: Usable): T { case 'fulfilled': { const fulfilledValue: T = thenable.value; hookLog.push({ + displayName: null, primitive: 'Promise', stackError: new Error(), value: fulfilledValue, @@ -187,6 +189,7 @@ function use(usable: Usable): T { // If this was an uncached Promise we have to abandon this attempt // but we can still emit anything up until this point. hookLog.push({ + displayName: null, primitive: 'Unresolved', stackError: new Error(), value: thenable, @@ -199,6 +202,7 @@ function use(usable: Usable): T { const value = readContext(context); hookLog.push({ + displayName: context.displayName || 'Context', primitive: 'Context (use)', stackError: new Error(), value, @@ -215,6 +219,7 @@ function use(usable: Usable): T { function useContext(context: ReactContext): T { hookLog.push({ + displayName: context.displayName || null, primitive: 'Context', stackError: new Error(), value: context._currentValue, @@ -235,6 +240,7 @@ function useState( initialState() : initialState; hookLog.push({ + displayName: null, primitive: 'State', stackError: new Error(), value: state, @@ -256,6 +262,7 @@ function useReducer( state = init !== undefined ? init(initialArg) : ((initialArg: any): S); } hookLog.push({ + displayName: null, primitive: 'Reducer', stackError: new Error(), value: state, @@ -268,6 +275,7 @@ function useRef(initialValue: T): {current: T} { const hook = nextHook(); const ref = hook !== null ? hook.memoizedState : {current: initialValue}; hookLog.push({ + displayName: null, primitive: 'Ref', stackError: new Error(), value: ref.current, @@ -279,6 +287,7 @@ function useRef(initialValue: T): {current: T} { function useCacheRefresh(): () => void { const hook = nextHook(); hookLog.push({ + displayName: null, primitive: 'CacheRefresh', stackError: new Error(), value: hook !== null ? hook.memoizedState : function refresh() {}, @@ -293,6 +302,7 @@ function useLayoutEffect( ): void { nextHook(); hookLog.push({ + displayName: null, primitive: 'LayoutEffect', stackError: new Error(), value: create, @@ -306,6 +316,7 @@ function useInsertionEffect( ): void { nextHook(); hookLog.push({ + displayName: null, primitive: 'InsertionEffect', stackError: new Error(), value: create, @@ -319,6 +330,7 @@ function useEffect( ): void { nextHook(); hookLog.push({ + displayName: null, primitive: 'Effect', stackError: new Error(), value: create, @@ -341,6 +353,7 @@ function useImperativeHandle( instance = ref.current; } hookLog.push({ + displayName: null, primitive: 'ImperativeHandle', stackError: new Error(), value: instance, @@ -350,6 +363,7 @@ function useImperativeHandle( function useDebugValue(value: any, formatterFn: ?(value: any) => any) { hookLog.push({ + displayName: null, primitive: 'DebugValue', stackError: new Error(), value: typeof formatterFn === 'function' ? formatterFn(value) : value, @@ -360,6 +374,7 @@ function useDebugValue(value: any, formatterFn: ?(value: any) => any) { function useCallback(callback: T, inputs: Array | void | null): T { const hook = nextHook(); hookLog.push({ + displayName: null, primitive: 'Callback', stackError: new Error(), value: hook !== null ? hook.memoizedState[0] : callback, @@ -375,6 +390,7 @@ function useMemo( const hook = nextHook(); const value = hook !== null ? hook.memoizedState[0] : nextCreate(); hookLog.push({ + displayName: null, primitive: 'Memo', stackError: new Error(), value, @@ -395,6 +411,7 @@ function useSyncExternalStore( nextHook(); // Effect const value = getSnapshot(); hookLog.push({ + displayName: null, primitive: 'SyncExternalStore', stackError: new Error(), value, @@ -413,6 +430,7 @@ function useTransition(): [ nextHook(); // State nextHook(); // Callback hookLog.push({ + displayName: null, primitive: 'Transition', stackError: new Error(), value: undefined, @@ -424,6 +442,7 @@ function useTransition(): [ function useDeferredValue(value: T, initialValue?: T): T { const hook = nextHook(); hookLog.push({ + displayName: null, primitive: 'DeferredValue', stackError: new Error(), value: hook !== null ? hook.memoizedState : value, @@ -436,6 +455,7 @@ function useId(): string { const hook = nextHook(); const id = hook !== null ? hook.memoizedState : ''; hookLog.push({ + displayName: null, primitive: 'Id', stackError: new Error(), value: id, @@ -485,6 +505,7 @@ function useOptimistic( state = passthrough; } hookLog.push({ + displayName: null, primitive: 'Optimistic', stackError: new Error(), value: state, @@ -507,6 +528,7 @@ function useFormState( state = initialState; } hookLog.push({ + displayName: null, primitive: 'FormState', stackError: new Error(), value: state, @@ -780,7 +802,7 @@ function buildTree( } prevStack = stack; } - const {primitive, debugInfo} = hook; + const {displayName, primitive, debugInfo} = hook; // For now, the "id" of stateful hooks is just the stateful hook index. // Custom hooks have no ids, nor do non-stateful native hooks (e.g. Context, DebugValue). @@ -795,7 +817,7 @@ function buildTree( // For the time being, only State and Reducer hooks support runtime overrides. const isStateEditable = primitive === 'Reducer' || primitive === 'State'; - const name = primitive === 'Context (use)' ? 'Context' : primitive; + const name = displayName || primitive; const levelChild: HooksNode = { id, isStateEditable, diff --git a/packages/react-debug-tools/src/__tests__/ReactHooksInspectionIntegration-test.js b/packages/react-debug-tools/src/__tests__/ReactHooksInspectionIntegration-test.js index 1fc54ef0f9102..1c6eea2606faf 100644 --- a/packages/react-debug-tools/src/__tests__/ReactHooksInspectionIntegration-test.js +++ b/packages/react-debug-tools/src/__tests__/ReactHooksInspectionIntegration-test.js @@ -772,8 +772,11 @@ describe('ReactHooksInspectionIntegration', () => { it('should inspect the value of the current provider in useContext', () => { const MyContext = React.createContext('default'); + const ThemeContext = React.createContext('default'); + ThemeContext.displayName = 'Theme'; function Foo(props) { const value = React.useContext(MyContext); + React.useContext(ThemeContext); return
{value}
; } const renderer = ReactTestRenderer.create( @@ -799,6 +802,20 @@ describe('ReactHooksInspectionIntegration', () => { "subHooks": [], "value": "contextual", }, + { + "debugInfo": null, + "hookSource": { + "columnNumber": 0, + "fileName": "**", + "functionName": "Foo", + "lineNumber": 0, + }, + "id": null, + "isStateEditable": false, + "name": "Theme", + "subHooks": [], + "value": "default", + }, ] `); });