Skip to content

Commit ad0bd14

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 967d46c commit ad0bd14

File tree

2 files changed

+82
-0
lines changed

2 files changed

+82
-0
lines changed

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

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import type {
1515
ReactProviderType,
1616
StartTransitionOptions,
1717
} from 'shared/ReactTypes';
18+
import {REACT_MEMO_CACHE_SENTINEL} from 'shared/ReactSymbols';
1819
import type {
1920
Fiber,
2021
Dispatcher as DispatcherType,
@@ -51,9 +52,19 @@ type Dispatch<A> = A => void;
5152

5253
let primitiveStackCache: null | Map<string, Array<any>> = null;
5354

55+
type MemoCache = {
56+
data: Array<Array<any>>,
57+
index: number,
58+
};
59+
60+
type FunctionComponentUpdateQueue = {
61+
memoCache?: MemoCache | null,
62+
};
63+
5464
type Hook = {
5565
memoizedState: any,
5666
next: Hook | null,
67+
updateQueue: FunctionComponentUpdateQueue | null,
5768
};
5869

5970
function getPrimitiveStackCache(): Map<string, Array<any>> {
@@ -79,6 +90,10 @@ function getPrimitiveStackCache(): Map<string, Array<any>> {
7990
Dispatcher.useDebugValue(null);
8091
Dispatcher.useCallback(() => {});
8192
Dispatcher.useMemo(() => null);
93+
if (typeof Dispatcher.useMemoCache === 'function') {
94+
// This type check is for Flow only.
95+
Dispatcher.useMemoCache(0);
96+
}
8297
} finally {
8398
readHookLog = hookLog;
8499
hookLog = [];
@@ -326,6 +341,37 @@ function useId(): string {
326341
return id;
327342
}
328343

344+
function useMemoCache(size: number): Array<any> {
345+
const hook = nextHook();
346+
let memoCache: MemoCache;
347+
if (
348+
hook !== null &&
349+
hook.updateQueue !== null &&
350+
hook.updateQueue.memoCache != null
351+
) {
352+
memoCache = hook.updateQueue.memoCache;
353+
} else {
354+
memoCache = {
355+
data: [],
356+
index: 0,
357+
};
358+
}
359+
360+
let data = memoCache.data[memoCache.index];
361+
if (data === undefined) {
362+
data = new Array(size);
363+
for (let i = 0; i < size; i++) {
364+
data[i] = REACT_MEMO_CACHE_SENTINEL;
365+
}
366+
}
367+
hookLog.push({
368+
primitive: 'MemoCache',
369+
stackError: new Error(),
370+
value: data,
371+
});
372+
return data;
373+
}
374+
329375
const Dispatcher: DispatcherType = {
330376
readContext,
331377
useCacheRefresh,
@@ -337,6 +383,7 @@ const Dispatcher: DispatcherType = {
337383
useLayoutEffect,
338384
useInsertionEffect,
339385
useMemo,
386+
useMemoCache,
340387
useReducer,
341388
useRef,
342389
useState,

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

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

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

0 commit comments

Comments
 (0)