eslint-plugin-react-usememo icon indicating copy to clipboard operation
eslint-plugin-react-usememo copied to clipboard

[BUG] Autofix creates infinite nested useMemo for spread operators in hook returns

Open Jahonny opened this issue 5 months ago • 0 comments

Minimal repro:

`// Original code in any React hook export function useBookDetails() { const bookDetails = { title: 'Example', author: 'Author' }; const dataLoaded = true;

return {
  ...bookDetails,
  dataLoaded,
};

}

After running eslint --fix once: return { ...useMemo(() => bookDetails, []), dataLoaded, };

After running eslint --fix again (adds ~10 more levels): return { ...useMemo(() => (useMemo(() => bookDetails, [])), []), dataLoaded, };

Each subsequent --fix adds more nesting indefinitely, eventually creating: return { ...useMemo(() => (useMemo(() => (useMemo(() => (useMemo(() => (useMemo(() => (useMemo(() => (useMemo(() => (useMemo(() => (useMemo(() => (useMemo(() => (bookDetails), [])), [])), [])), [])), [])), [])), [])), [])), [])), []), dataLoaded, };`

Installed packages versions: ESLint: 9.16.0 Eslint-plugin-react-usememo: 2.5.0

Rule and its options: '@arthurgeron/react-usememo/require-usememo': [ 'warn', { strict: false, checkHookCalls: false, }, ]

Error log / Stack trace: No error is thrown. The issue is that the autofix repeatedly wraps already-memoized spread operators, creating increasingly nested useMemo calls. This makes the autofix feature unusable for any hooks that return objects with spread operators.

Impact: In our codebase, 3 hook files accumulated 10-40 levels of nested useMemo, adding ~365 ESLint errors from just these files.

Expected behavior: The plugin should recognize when a spread operator is already wrapped in useMemo and not add additional layers.

Actual behavior: The plugin doesn't recognize its own useMemo wrapping and continuously adds more layers each time --fix is run.

Jahonny avatar Jul 14 '25 23:07 Jahonny