Skip to content

Commit bd36112

Browse files
committed
[DevTools] Add support for useMemoCache
useMemoCache wasn't previously supported in the DevTools, so any attempt to inspect a component using the hook would result in a `dispatcher.useMemoCache is not a function (it is undefined)` error.
1 parent 2fa6323 commit bd36112

File tree

2 files changed

+84
-0
lines changed

2 files changed

+84
-0
lines changed

packages/react-debug-tools/src/ReactDebugHooks.js

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ import {
3030
ForwardRef,
3131
} from 'react-reconciler/src/ReactWorkTags';
3232

33+
const MEMO_CACHE_SENTINEL = Symbol.for('react.memo_cache_sentinel');
34+
3335
type CurrentDispatcherRef = typeof ReactSharedInternals.ReactCurrentDispatcher;
3436

3537
// Used to track hooks called during a render
@@ -51,9 +53,19 @@ type Dispatch<A> = A => void;
5153

5254
let primitiveStackCache: null | Map<string, Array<any>> = null;
5355

56+
type MemoCache = {
57+
data: Array<Array<any>>,
58+
index: number,
59+
};
60+
61+
type FunctionComponentUpdateQueue = {
62+
memoCache?: MemoCache | null,
63+
};
64+
5465
type Hook = {
5566
memoizedState: any,
5667
next: Hook | null,
68+
updateQueue: FunctionComponentUpdateQueue | null,
5769
};
5870

5971
function getPrimitiveStackCache(): Map<string, Array<any>> {
@@ -79,6 +91,10 @@ function getPrimitiveStackCache(): Map<string, Array<any>> {
7991
Dispatcher.useDebugValue(null);
8092
Dispatcher.useCallback(() => {});
8193
Dispatcher.useMemo(() => null);
94+
if (typeof Dispatcher.useMemoCache === 'function') {
95+
// This type check is for Flow only.
96+
Dispatcher.useMemoCache(0);
97+
}
8298
} finally {
8399
readHookLog = hookLog;
84100
hookLog = [];
@@ -333,6 +349,37 @@ function useId(): string {
333349
return id;
334350
}
335351

352+
function useMemoCache(size: number): Array<any> {
353+
const hook = nextHook();
354+
let memoCache: MemoCache;
355+
if (
356+
hook !== null &&
357+
hook.updateQueue !== null &&
358+
hook.updateQueue.memoCache != null
359+
) {
360+
memoCache = hook.updateQueue.memoCache;
361+
} else {
362+
memoCache = {
363+
data: [],
364+
index: 0,
365+
};
366+
}
367+
368+
let data = memoCache.data[memoCache.index];
369+
if (data === undefined) {
370+
data = new Array(size);
371+
for (let i = 0; i < size; i++) {
372+
data[i] = MEMO_CACHE_SENTINEL;
373+
}
374+
}
375+
hookLog.push({
376+
primitive: 'MemoCache',
377+
stackError: new Error(),
378+
value: data,
379+
});
380+
return data;
381+
}
382+
336383
const Dispatcher: DispatcherType = {
337384
use,
338385
readContext,
@@ -345,6 +392,7 @@ const Dispatcher: DispatcherType = {
345392
useLayoutEffect,
346393
useInsertionEffect,
347394
useMemo,
395+
useMemoCache,
348396
useReducer,
349397
useRef,
350398
useState,

packages/react-debug-tools/src/__tests__/ReactHooksInspectionIntegration-test.js

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -633,6 +633,42 @@ describe('ReactHooksInspectionIntegration', () => {
633633
});
634634
});
635635

636+
// @gate enableUseMemoCacheHook
637+
it('should support useMemoCache hook', () => {
638+
function Foo() {
639+
const $ = React.unstable_useMemoCache(1);
640+
let t0;
641+
642+
if ($[0] === Symbol.for('react.memo_cache_sentinel')) {
643+
t0 = <div>{1}</div>;
644+
$[0] = t0;
645+
} else {
646+
t0 = $[0];
647+
}
648+
649+
return t0;
650+
}
651+
652+
const renderer = ReactTestRenderer.create(<Foo />);
653+
const childFiber = renderer.root.findByType(Foo)._currentFiber();
654+
const tree = ReactDebugTools.inspectHooksOfFiber(childFiber);
655+
656+
expect(tree.length).toEqual(1);
657+
expect(tree[0]).toMatchInlineSnapshot(`
658+
{
659+
"id": 0,
660+
"isStateEditable": false,
661+
"name": "MemoCache",
662+
"subHooks": [],
663+
"value": [
664+
<div>
665+
1
666+
</div>,
667+
],
668+
}
669+
`);
670+
});
671+
636672
describe('useDebugValue', () => {
637673
it('should support inspectable values for multiple custom hooks', () => {
638674
function useLabeledValue(label) {

0 commit comments

Comments
 (0)