logo by @sawaratsuki1004
React
v19.2
Learn
Reference
Community
Blog

Is this page useful?

On this page

  • Overview
  • Rule Details
  • Invalid
  • Valid
  • Troubleshooting
  • I need to run side effects when dependencies change

    react@19.2

  • Overview
  • Hooks
    • useActionState
    • useCallback
    • useContext
    • useDebugValue
    • useDeferredValue
    • useEffect
    • useEffectEvent
    • useId
    • useImperativeHandle
    • useInsertionEffect
    • useLayoutEffect
    • useMemo
    • useOptimistic
    • useReducer
    • useRef
    • useState
    • useSyncExternalStore
    • useTransition
  • Components
    • <Fragment> (<>)
    • <Profiler>
    • <StrictMode>
    • <Suspense>
    • <Activity>
    • <ViewTransition> - This feature is available in the latest Canary version of React
  • APIs
    • act
    • addTransitionType - This feature is available in the latest Canary version of React
    • cache
    • cacheSignal
    • captureOwnerStack
    • createContext
    • lazy
    • memo
    • startTransition
    • use
    • experimental_taintObjectReference - This feature is available in the latest Experimental version of React
    • experimental_taintUniqueValue - This feature is available in the latest Experimental version of React
  • react-dom@19.2

  • Hooks
    • useFormStatus
  • Components
    • Common (e.g. <div>)
    • <form>
    • <input>
    • <option>
    • <progress>
    • <select>
    • <textarea>
    • <link>
    • <meta>
    • <script>
    • <style>
    • <title>
  • APIs
    • createPortal
    • flushSync
    • preconnect
    • prefetchDNS
    • preinit
    • preinitModule
    • preload
    • preloadModule
  • Client APIs
    • createRoot
    • hydrateRoot
  • Server APIs
    • renderToPipeableStream
    • renderToReadableStream
    • renderToStaticMarkup
    • renderToString
    • resume
    • resumeToPipeableStream
  • Static APIs
    • prerender
    • prerenderToNodeStream
    • resumeAndPrerender
    • resumeAndPrerenderToNodeStream
  • React Compiler

  • Configuration
    • compilationMode
    • gating
    • logger
    • panicThreshold
    • target
  • Directives
    • "use memo"
    • "use no memo"
  • Compiling Libraries
  • React DevTools

  • React Performance tracks
  • eslint-plugin-react-hooks

  • Lints
    • exhaustive-deps
    • rules-of-hooks
    • component-hook-factories
    • config
    • error-boundaries
    • gating
    • globals
    • immutability
    • incompatible-library
    • preserve-manual-memoization
    • purity
    • refs
    • set-state-in-effect
    • set-state-in-render
    • static-components
    • unsupported-syntax
    • use-memo
  • Rules of React

  • Overview
    • Components and Hooks must be pure
    • React calls Components and Hooks
    • Rules of Hooks
  • React Server Components

  • Server Components
  • Server Functions
  • Directives
    • 'use client'
    • 'use server'
  • Legacy APIs

  • Legacy React APIs
    • Children
    • cloneElement
    • Component
    • createElement
    • createRef
    • forwardRef
    • isValidElement
    • PureComponent
API Reference

use-memo

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

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

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

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

I need to run side effects when dependencies change

You might try to use useMemo for side effects:

// ❌ 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>; }


Copyright © Meta Platforms, Inc
no uwu plz
uwu?
Logo by@sawaratsuki1004
Learn React
Quick Start
Installation
Describing the UI
Adding Interactivity
Managing State
Escape Hatches
API Reference
React APIs
React DOM APIs
Community
Code of Conduct
Meet the Team
Docs Contributors
Acknowledgements
More
Blog
React Native
Privacy
Terms
// ❌ No return value
function Component({ data }) {
const processed = useMemo(() => {
data.forEach(item => console.log(item));
// Missing return!
}, [data]);

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

return <div>{processed}</div>;
}
// ❌ 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]);
}
// ✅ 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>;
}
// ✅ Good: Synchronization in useEffect
function Component({theme}) {
useEffect(() => {
localStorage.setItem('preferredTheme', theme);
document.body.className = theme;
}, [theme]);

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