@samitouri / QOS-React-2 / commits / 85cc01743b

DevTools: Add support for useOptimistic Hook (#27982)

## Summary Add support for `useOptimistic` Hook fixing "Unsupported hook in the react-debug-tools package: Missing method in Dispatcher: useOptimistic" when inspecting components using `useOptimistic` ## How did you test this change? - Added test following the same pattern as for `useDeferredValue`

Sebastian Silbermann committed Feb 2, 2024 at 23:18 UTC 85cc01743bc992a689770a4f37e3d5441f14f082
3 files changed +65
packages/react-debug-tools/src/ReactDebugHooks.js
+25
@@ -80,6 +80,11 @@ function getPrimitiveStackCache(): Map<string, Array<any>> {
80 // This type check is for Flow only.
81 Dispatcher.useMemoCache(0);
82 }
83 +
84 + if (typeof Dispatcher.useOptimistic === 'function') {
85 + // This type check is for Flow only.
86 + Dispatcher.useOptimistic(null, (s: mixed, a: mixed) => s);
87 + }
88 } finally {
89 readHookLog = hookLog;
90 hookLog = [];
@@ -348,6 +353,25 @@ function useMemoCache(size: number): Array<any> {
353 return data;
354 }
355
356 +function useOptimistic<S, A>(
357 + passthrough: S,
358 + reducer: ?(S, A) => S,
359 +): [S, (A) => void] {
360 + const hook = nextHook();
361 + let state;
362 + if (hook !== null) {
363 + state = hook.memoizedState;
364 + } else {
365 + state = passthrough;
366 + }
367 + hookLog.push({
368 + primitive: 'Optimistic',
369 + stackError: new Error(),
370 + value: state,
371 + });
372 + return [state, (action: A) => {}];
373 +}
374 +
375 const Dispatcher: DispatcherType = {
376 use,
377 readContext,
@@ -361,6 +385,7 @@ const Dispatcher: DispatcherType = {
385 useInsertionEffect,
386 useMemo,
387 useMemoCache,
388 + useOptimistic,
389 useReducer,
390 useRef,
391 useState,
packages/react-debug-tools/src/__tests__/ReactHooksInspectionIntegration-test.js
+38
@@ -1106,4 +1106,42 @@ describe('ReactHooksInspectionIntegration', () => {
1106 },
1107 ]);
1108 });
1109 +
1110 + // @gate enableAsyncActions
1111 + it('should support useOptimistic hook', () => {
1112 + const useOptimistic = React.useOptimistic;
1113 + function Foo() {
1114 + const [value] = useOptimistic('abc', currentState => currentState);
1115 + React.useMemo(() => 'memo', []);
1116 + React.useMemo(() => 'not used', []);
1117 + return value;
1118 + }
1119 +
1120 + const renderer = ReactTestRenderer.create(<Foo />);
1121 + const childFiber = renderer.root.findByType(Foo)._currentFiber();
1122 + const tree = ReactDebugTools.inspectHooksOfFiber(childFiber);
1123 + expect(tree).toEqual([
1124 + {
1125 + id: 0,
1126 + isStateEditable: false,
1127 + name: 'Optimistic',
1128 + value: 'abc',
1129 + subHooks: [],
1130 + },
1131 + {
1132 + id: 1,
1133 + isStateEditable: false,
1134 + name: 'Memo',
1135 + value: 'memo',
1136 + subHooks: [],
1137 + },
1138 + {
1139 + id: 2,
1140 + isStateEditable: false,
1141 + name: 'Memo',
1142 + value: 'not used',
1143 + subHooks: [],
1144 + },
1145 + ]);
1146 + });
1147 });
packages/react-devtools-shell/src/app/InspectableElements/CustomHooks.js
+2
@@ -17,6 +17,7 @@ import {
17 useContext,
18 useDebugValue,
19 useEffect,
20 + useOptimistic,
21 useState,
22 } from 'react';
23
@@ -73,6 +74,7 @@ function FunctionWithHooks(props: any, ref: React$Ref<any>) {
74 const [count, updateCount] = useState(0);
75 // eslint-disable-next-line no-unused-vars
76 const contextValueA = useContext(ContextA);
77 + useOptimistic<number, mixed>(1);
78
79 // eslint-disable-next-line no-unused-vars
80 const [_, __] = useState(object);