diff --git a/packages/react-debug-tools/src/ReactDebugHooks.js b/packages/react-debug-tools/src/ReactDebugHooks.js index d515bac08e9b9..c2d3ed0a2accf 100644 --- a/packages/react-debug-tools/src/ReactDebugHooks.js +++ b/packages/react-debug-tools/src/ReactDebugHooks.js @@ -243,7 +243,11 @@ function useResponder( function useTransition( config: SuspenseConfig | null | void, ): [(() => void) => void, boolean] { - nextHook(); + // useTransition() composes multiple hooks internally. + // Advance the current hook index the same number of times + // so that subsequent hooks have the right memoized state. + nextHook(); // State + nextHook(); // Callback hookLog.push({ primitive: 'Transition', stackError: new Error(), @@ -253,7 +257,11 @@ function useTransition( } function useDeferredValue(value: T, config: TimeoutConfig | null | void): T { - nextHook(); + // useDeferredValue() composes multiple hooks internally. + // Advance the current hook index the same number of times + // so that subsequent hooks have the right memoized state. + nextHook(); // State + nextHook(); // Effect hookLog.push({ primitive: 'DeferredValue', stackError: new Error(), diff --git a/packages/react-debug-tools/src/__tests__/ReactHooksInspectionIntegration-test.js b/packages/react-debug-tools/src/__tests__/ReactHooksInspectionIntegration-test.js index a3542d86ceba3..f92191beaf217 100644 --- a/packages/react-debug-tools/src/__tests__/ReactHooksInspectionIntegration-test.js +++ b/packages/react-debug-tools/src/__tests__/ReactHooksInspectionIntegration-test.js @@ -366,6 +366,64 @@ describe('ReactHooksInspectionIntegration', () => { ]); }); + if (__EXPERIMENTAL__) { + it('should support composite useTransition hook', () => { + function Foo(props) { + React.useTransition(); + const memoizedValue = React.useMemo(() => 'hello', []); + return
{memoizedValue}
; + } + let renderer = ReactTestRenderer.create(); + let childFiber = renderer.root.findByType(Foo)._currentFiber(); + let tree = ReactDebugTools.inspectHooksOfFiber(childFiber); + expect(tree).toEqual([ + { + id: 0, + isStateEditable: false, + name: 'Transition', + value: undefined, + subHooks: [], + }, + { + id: 1, + isStateEditable: false, + name: 'Memo', + value: 'hello', + subHooks: [], + }, + ]); + }); + + it('should support composite useDeferredValue hook', () => { + function Foo(props) { + React.useDeferredValue('abc', { + timeoutMs: 500, + }); + const [state] = React.useState(() => 'hello', []); + return
{state}
; + } + let renderer = ReactTestRenderer.create(); + let childFiber = renderer.root.findByType(Foo)._currentFiber(); + let tree = ReactDebugTools.inspectHooksOfFiber(childFiber); + expect(tree).toEqual([ + { + id: 0, + isStateEditable: false, + name: 'DeferredValue', + value: 'abc', + subHooks: [], + }, + { + id: 1, + isStateEditable: true, + name: 'State', + value: 'hello', + subHooks: [], + }, + ]); + }); + } + describe('useDebugValue', () => { it('should support inspectable values for multiple custom hooks', () => { function useLabeledValue(label) {