Skip to content

Commit

Permalink
DevTools: Add support for useOptimistic Hook (#27982)
Browse files Browse the repository at this point in the history
## 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`
  • Loading branch information
eps1lon authored and gaearon committed Feb 3, 2024
1 parent d73157d commit d4b8a3b
Show file tree
Hide file tree
Showing 3 changed files with 65 additions and 0 deletions.
25 changes: 25 additions & 0 deletions packages/react-debug-tools/src/ReactDebugHooks.js
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,11 @@ function getPrimitiveStackCache(): Map<string, Array<any>> {
// This type check is for Flow only.
Dispatcher.useMemoCache(0);
}

if (typeof Dispatcher.useOptimistic === 'function') {
// This type check is for Flow only.
Dispatcher.useOptimistic(null, (s: mixed, a: mixed) => s);
}
} finally {
readHookLog = hookLog;
hookLog = [];
Expand Down Expand Up @@ -348,6 +353,25 @@ function useMemoCache(size: number): Array<any> {
return data;
}

function useOptimistic<S, A>(
passthrough: S,
reducer: ?(S, A) => S,
): [S, (A) => void] {
const hook = nextHook();
let state;
if (hook !== null) {
state = hook.memoizedState;
} else {
state = passthrough;
}
hookLog.push({
primitive: 'Optimistic',
stackError: new Error(),
value: state,
});
return [state, (action: A) => {}];
}

const Dispatcher: DispatcherType = {
use,
readContext,
Expand All @@ -361,6 +385,7 @@ const Dispatcher: DispatcherType = {
useInsertionEffect,
useMemo,
useMemoCache,
useOptimistic,
useReducer,
useRef,
useState,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1106,4 +1106,42 @@ describe('ReactHooksInspectionIntegration', () => {
},
]);
});

// @gate enableAsyncActions
it('should support useOptimistic hook', () => {
const useOptimistic = React.useOptimistic;
function Foo() {
const [value] = useOptimistic('abc', currentState => currentState);
React.useMemo(() => 'memo', []);
React.useMemo(() => 'not used', []);
return value;
}

const renderer = ReactTestRenderer.create(<Foo />);
const childFiber = renderer.root.findByType(Foo)._currentFiber();
const tree = ReactDebugTools.inspectHooksOfFiber(childFiber);
expect(tree).toEqual([
{
id: 0,
isStateEditable: false,
name: 'Optimistic',
value: 'abc',
subHooks: [],
},
{
id: 1,
isStateEditable: false,
name: 'Memo',
value: 'memo',
subHooks: [],
},
{
id: 2,
isStateEditable: false,
name: 'Memo',
value: 'not used',
subHooks: [],
},
]);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import {
useContext,
useDebugValue,
useEffect,
useOptimistic,
useState,
} from 'react';

Expand Down Expand Up @@ -73,6 +74,7 @@ function FunctionWithHooks(props: any, ref: React$Ref<any>) {
const [count, updateCount] = useState(0);
// eslint-disable-next-line no-unused-vars
const contextValueA = useContext(ContextA);
useOptimistic<number, mixed>(1);

// eslint-disable-next-line no-unused-vars
const [_, __] = useState(object);
Expand Down

0 comments on commit d4b8a3b

Please sign in to comment.