Repository: facebook/react
Pull request: fix[devtools/useMemoCache]: add stub for useMemoCache in ReactDebugHook

Currently, we have this error in our logs of the internal version of React DevTools:
```
TypeError: Cannot read properties of undefined (reading 'memoCache')
    at Proxy.useMemoCache (chrome-extension://dnjnjgbfilfphmojnmhliehogmojhclc/build/react_devtools_backend_compact.js:151:71)
```

Looking at the build files of the extension, it fails here: https://github.com/facebook/react/blob/dddfe688206dafa5646550d351eb9a8e9c53654a/packages/react-debug-tools/src/ReactDebugHooks.js#L333-L337

Looks like `updateQueue` can be `undefined`, as it is not defined in hook object here: https://github.com/facebook/react/blob/dddfe688206dafa5646550d351eb9a8e9c53654a/packages/react-reconciler/src/ReactFiberHooks.js#L180-L186

~~Also, it looks like `useMemoCache` implementation doesn't expect this, so it should also result into TypeError here, line 1114:~~
https://github.com/facebook/react/blob/dddfe688206dafa5646550d351eb9a8e9c53654a/packages/react-reconciler/src/ReactFiberHooks.js#L1108-L1115

~~Should this also be updated?~~

Changed files:
filename: packages/react-debug-tools/src/ReactDebugHooks.js
patch: @@ -48,19 +48,9 @@ type Dispatch<A> = A => void;
 
 let primitiveStackCache: null | Map<string, Array<any>> = null;
 
-type MemoCache = {
-  data: Array<Array<any>>,
-  index: number,
-};
-
-type FunctionComponentUpdateQueue = {
-  memoCache?: MemoCache | null,
-};
-
 type Hook = {
   memoizedState: any,
   next: Hook | null,
-  updateQueue: FunctionComponentUpdateQueue | null,
 };
 
 function getPrimitiveStackCache(): Map<string, Array<any>> {
@@ -327,36 +317,11 @@ function useId(): string {
   return id;
 }
 
+// useMemoCache is an implementation detail of Forget's memoization
+// it should not be called directly in user-generated code
+// we keep it as a stub for dispatcher
 function useMemoCache(size: number): Array<any> {
-  const hook = nextHook();
-  let memoCache: MemoCache;
-  if (
-    hook !== null &&
-    hook.updateQueue !== null &&
-    hook.updateQueue.memoCache != null
-  ) {
-    memoCache = hook.updateQueue.memoCache;
-  } else {
-    memoCache = {
-      data: [],
-      index: 0,
-    };
-  }
-
-  let data = memoCache.data[memoCache.index];
-  if (data === undefined) {
-    const MEMO_CACHE_SENTINEL = Symbol.for('react.memo_cache_sentinel');
-    data = new Array(size);
-    for (let i = 0; i < size; i++) {
-      data[i] = MEMO_CACHE_SENTINEL;
-    }
-  }
-  hookLog.push({
-    primitive: 'MemoCache',
-    stackError: new Error(),
-    value: data,
-  });
-  return data;
+  return [];
 }
 
 const Dispatcher: DispatcherType = {
@@ -725,7 +690,7 @@ export function inspectHooks<Props>(
   renderFunction: Props => React$Node,
   props: Props,
   currentDispatcher: ?CurrentDispatcherRef,
-  includeHooksSource?: boolean = false,
+  includeHooksSource: boolean = false,
 ): HooksTree {
   // DevTools will pass the current renderer's injected dispatcher.
   // Other apps might compile debug hooks as part of their app though.
@@ -816,7 +781,7 @@ function resolveDefaultProps(Component: any, baseProps: any) {
 export function inspectHooksOfFiber(
   fiber: Fiber,
   currentDispatcher: ?CurrentDispatcherRef,
-  includeHooksSource?: boolean = false,
+  includeHooksSource: boolean = false,
 ): HooksTree {
   // DevTools will pass the current renderer's injected dispatcher.
   // Other apps might compile debug hooks as part of their app though.

filename: packages/react-debug-tools/src/__tests__/ReactHooksInspectionIntegration-test.js
patch: @@ -634,7 +634,7 @@ describe('ReactHooksInspectionIntegration', () => {
   });
 
   // @gate enableUseMemoCacheHook
-  it('should support useMemoCache hook', () => {
+  it('useMemoCache should not be inspectable', () => {
     function Foo() {
       const $ = useMemoCache(1);
       let t0;
@@ -653,11 +653,7 @@ describe('ReactHooksInspectionIntegration', () => {
     const childFiber = renderer.root.findByType(Foo)._currentFiber();
     const tree = ReactDebugTools.inspectHooksOfFiber(childFiber);
 
-    expect(tree.length).toEqual(1);
-    expect(tree[0].isStateEditable).toBe(false);
-    expect(tree[0].name).toBe('MemoCache');
-    expect(tree[0].value).toHaveLength(1);
-    expect(tree[0].value[0]).toEqual(<div>{1}</div>);
+    expect(tree.length).toEqual(0);
   });
 
   describe('useDebugValue', () => {

filename: packages/react-devtools-shell/src/app/InspectableElements/InspectableElements.js
patch: @@ -18,6 +18,7 @@ import EdgeCaseObjects from './EdgeCaseObjects.js';
 import NestedProps from './NestedProps';
 import SimpleValues from './SimpleValues';
 import SymbolKeys from './SymbolKeys';
+import UseMemoCache from './UseMemoCache';
 
 // TODO Add Immutable JS example
 
@@ -34,6 +35,7 @@ export default function InspectableElements(): React.Node {
       <EdgeCaseObjects />
       <CircularReferences />
       <SymbolKeys />
+      <UseMemoCache />
     </Fragment>
   );
 }

filename: packages/react-devtools-shell/src/app/InspectableElements/UseMemoCache.js
patch: @@ -0,0 +1,7 @@
+import * as React from 'react';
+
+export default function UseMemoCache(): React.Node {
+  React.unstable_useMemoCache(1);
+
+  return null;
+}