Files
react.dev/src/content/reference/eslint-plugin-react-hooks/lints/use-memo.md
Ricky c3d7560005 Blog post for React 19.2 (#8028)
* wip

* feedback and rm canary stuff

* tweak

* fix json

* more canary stuff

* fix link

* update dates

* update meta description

* Expand performance track section

* adjust linter note

* edit perf tracks down

* edit perf tracks down more

* tweak note

* tweak useEffectEvent

* formatting

* tweaks

* ppr

* rm canary stuff

* fix json

* fix json

* tweaks

* linter note

* nit

* nit

* link

* nit

* ppr

* missing await

* add lint v6

* fix link

---------

Co-authored-by: Dan Abramov <dan.abramov@gmail.com>
2025-10-01 17:42:52 -04:00

2.4 KiB

title, version
title version
use-memo rc

Validates that the useMemo hook is used with a return value. See useMemo docs for more information.

This rule is available in eslint-plugin-react-hooks v6.

Rule Details {/rule-details/}

useMemo is for computing and caching expensive values, not for side effects. Without a return value, useMemo returns undefined, which defeats its purpose and likely indicates you're using the wrong hook.

Invalid {/invalid/}

Examples of incorrect code for this rule:

// ❌ No return value
function Component({ data }) {
  const processed = useMemo(() => {
    data.forEach(item => console.log(item));
    // Missing return!
  }, [data]);

  return <div>{processed}</div>; // Always undefined
}

Valid {/valid/}

Examples of correct code for this rule:

// ✅ Returns computed value
function Component({ data }) {
  const processed = useMemo(() => {
    return data.map(item => item * 2);
  }, [data]);

  return <div>{processed}</div>;
}

Troubleshooting {/troubleshooting/}

I need to run side effects when dependencies change {/side-effects/}

You might try to use useMemo for side effects:

{/* TODO(@poteto) fix compiler validation to check for unassigned useMemos */}

// ❌ Wrong: Side effects in useMemo
function Component({user}) {
  // No return value, just side effect
  useMemo(() => {
    analytics.track('UserViewed', {userId: user.id});
  }, [user.id]);

  // Not assigned to a variable
  useMemo(() => {
    return analytics.track('UserViewed', {userId: user.id});
  }, [user.id]);
}

If the side effect needs to happen in response to user interaction, it's best to colocate the side effect with the event:

// ✅ Good: Side effects in event handlers
function Component({user}) {
  const handleClick = () => {
    analytics.track('ButtonClicked', {userId: user.id});
    // Other click logic...
  };

  return <button onClick={handleClick}>Click me</button>;
}

If the side effect sychronizes React state with some external state (or vice versa), use useEffect:

// ✅ Good: Synchronization in useEffect
function Component({theme}) {
  useEffect(() => {
    localStorage.setItem('preferredTheme', theme);
    document.body.className = theme;
  }, [theme]);

  return <div>Current theme: {theme}</div>;
}