Skip to content

Commit

Permalink
fix[devtools/useMemoCache]: add stub for useMemoCache in ReactDebugHo…
Browse files Browse the repository at this point in the history
…ok (#27472)

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?~~
  • Loading branch information
hoxyq authored Oct 17, 2023
1 parent 75c1bd7 commit a419575
Show file tree
Hide file tree
Showing 4 changed files with 17 additions and 47 deletions.
47 changes: 6 additions & 41 deletions packages/react-debug-tools/src/ReactDebugHooks.js
Original file line number Diff line number Diff line change
Expand Up @@ -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>> {
Expand Down Expand Up @@ -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 = {
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -34,6 +35,7 @@ export default function InspectableElements(): React.Node {
<EdgeCaseObjects />
<CircularReferences />
<SymbolKeys />
<UseMemoCache />
</Fragment>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import * as React from 'react';

export default function UseMemoCache(): React.Node {
React.unstable_useMemoCache(1);

return null;
}

0 comments on commit a419575

Please sign in to comment.