diff --git a/packages/react-debug-tools/src/ReactDebugHooks.js b/packages/react-debug-tools/src/ReactDebugHooks.js index 0e2364f672b70..131a0003dcec7 100644 --- a/packages/react-debug-tools/src/ReactDebugHooks.js +++ b/packages/react-debug-tools/src/ReactDebugHooks.js @@ -269,7 +269,19 @@ function useSyncExternalStore( subscribe: (() => void) => () => void, getSnapshot: () => T, ): T { - throw new Error('Not yet implemented'); + // useSyncExternalStore() composes multiple hooks internally. + // Advance the current hook index the same number of times + // so that subsequent hooks have the right memoized state. + nextHook(); // SyncExternalStore + nextHook(); // LayoutEffect + nextHook(); // Effect + const value = getSnapshot(); + hookLog.push({ + primitive: 'SyncExternalStore', + stackError: new Error(), + value, + }); + return value; } function useTransition(): [boolean, (() => void) => void] { diff --git a/packages/react-debug-tools/src/__tests__/ReactHooksInspectionIntegration-test.js b/packages/react-debug-tools/src/__tests__/ReactHooksInspectionIntegration-test.js index 1a35fd284c906..1c7cb75088408 100644 --- a/packages/react-debug-tools/src/__tests__/ReactHooksInspectionIntegration-test.js +++ b/packages/react-debug-tools/src/__tests__/ReactHooksInspectionIntegration-test.js @@ -878,4 +878,37 @@ describe('ReactHooksInspectionIntegration', () => { }, ]); }); + + // @gate experimental || www + it('should support composite useSyncExternalStore hook', () => { + const useSyncExternalStore = React.unstable_useSyncExternalStore; + function Foo() { + const value = useSyncExternalStore( + () => () => {}, + () => 'snapshot', + ); + React.useMemo(() => 'memo', []); + return value; + } + + const renderer = ReactTestRenderer.create(); + const childFiber = renderer.root.findByType(Foo)._currentFiber(); + const tree = ReactDebugTools.inspectHooksOfFiber(childFiber); + expect(tree).toEqual([ + { + id: 0, + isStateEditable: false, + name: 'SyncExternalStore', + value: 'snapshot', + subHooks: [], + }, + { + id: 1, + isStateEditable: false, + name: 'Memo', + value: 'memo', + subHooks: [], + }, + ]); + }); });