[{"data":1,"prerenderedAt":116},["ShallowReactive",2],{"qa-\u002Freact\u002Frendering-and-performance\u002Fusememo-usecallback-patterns":3},{"page":4,"siblings":96,"blog":113},{"id":5,"title":6,"body":7,"description":11,"difficulty":14,"extension":15,"framework":16,"frameworkSlug":17,"meta":18,"navigation":20,"order":21,"path":22,"questions":23,"questionsCount":86,"related":87,"seo":88,"seoDescription":89,"stem":90,"subtopic":91,"topic":92,"topicSlug":93,"updated":94,"__hash__":95},"qa\u002Freact\u002Frendering-and-performance\u002Fusememo-usecallback-patterns.md","Usememo Usecallback Patterns",{"type":8,"value":9,"toc":10},"minimark",[],{"title":11,"searchDepth":12,"depth":12,"links":13},"",2,[],"medium","md","React","react",{"subtopicSlug":19},"usememo-usecallback-patterns",true,3,"\u002Freact\u002Frendering-and-performance\u002Fusememo-usecallback-patterns",[24,29,33,37,41,45,49,53,58,62,66,70,74,78,82],{"id":25,"difficulty":26,"q":27,"a":28},"what-is-usememo","easy","What does useMemo do and what problem does it solve?","`useMemo` is a React hook that **caches the result of a computation**\nbetween renders. It re-runs the factory function only when one of its\nlisted **dependencies** changes; otherwise it returns the previously\ncached value.\n\n```jsx\nfunction ProductList({ products, filterText }) {\n  \u002F\u002F Without useMemo: filtered every render even if products\u002FfilterText\n  \u002F\u002F haven't changed\n  const filtered = useMemo(\n    () => products.filter(p => p.name.includes(filterText)),\n    [products, filterText] \u002F\u002F only re-compute when these change\n  )\n\n  return filtered.map(p => \u003CProductRow key={p.id} product={p} \u002F>)\n}\n```\n\nThe problem it solves is twofold. First, it avoids **re-running\nexpensive computations** on every render. Second, it preserves\n**referential identity** of objects and arrays so downstream\n`React.memo` comparisons and `useEffect` dependency checks don't\nfire unnecessarily.\n\n**Rule of thumb:** Only reach for `useMemo` when the computation is\nmeasurably expensive or when referential stability of the returned\nvalue is required by a consumer — not as a default wrapping strategy.\n",{"id":30,"difficulty":26,"q":31,"a":32},"what-is-usecallback","What does useCallback do and how is it different from useMemo?","`useCallback` **memoizes a function reference** so the same function\nobject is returned across renders as long as its dependencies stay the\nsame. It is syntactic sugar over `useMemo` returning a function.\n\n```jsx\n\u002F\u002F These two are equivalent:\nconst handleClick = useCallback(() => {\n  doSomething(id)\n}, [id])\n\nconst handleClick = useMemo(() => () => {\n  doSomething(id)\n}, [id])\n```\n\nThe key difference in intent:\n- `useMemo` — memoize a **computed value** (object, array, number…)\n- `useCallback` — memoize a **function definition** so its reference\n  stays stable\n\nBoth return a cached result; `useCallback` is just the idiomatic form\nwhen that result is a function.\n\n**Rule of thumb:** Use `useCallback` when you need a stable function\nreference to pass as a prop to a memoized child or as a dependency\ninside a `useEffect` — not to speed up the call itself.\n",{"id":34,"difficulty":26,"q":35,"a":36},"dependency-arrays-explained","How do dependency arrays work in useMemo and useCallback?","The **dependency array** is the second argument to both hooks. React\ncompares each element of the array to its previous value using\n`Object.is` after every render. If any element changed, the cached\nvalue is discarded and the factory function re-runs.\n\n```jsx\nconst total = useMemo(() => {\n  return items.reduce((sum, item) => sum + item.price, 0)\n}, [items]) \u002F\u002F re-compute only when `items` reference changes\n\n\u002F\u002F Common mistakes:\n\u002F\u002F [] — never re-computes (stale data if items changes)\n\u002F\u002F no array — re-computes every render (defeats memoisation)\n\u002F\u002F [items.length] — misses mutations that don't change length\n```\n\nReact's ESLint plugin (`eslint-plugin-react-hooks`) enforces the\n**exhaustive-deps** rule, which flags any value used inside the\nfactory that is missing from the dependency array. This prevents\n**stale closure bugs** at the cost of occasionally breaking\nmemoisation when a dependency changes too often.\n\n**Rule of thumb:** Always list every reactive value read inside the\nfactory; rely on `eslint-plugin-react-hooks` to catch omissions\nautomatically.\n",{"id":38,"difficulty":14,"q":39,"a":40},"referential-stability","What is referential stability and why does it matter for memoization?","**Referential stability** means an object or function returns the\nsame memory reference across renders. In JavaScript, two objects\nwith identical contents are still different values under `Object.is`,\nwhich is what React uses for prop comparison and dependency checks.\n\n```jsx\nfunction Parent() {\n  \u002F\u002F NEW object reference every render — breaks child memo\n  const style = { color: 'red' }\n\n  \u002F\u002F STABLE reference — child memo works\n  const style = useMemo(() => ({ color: 'red' }), [])\n\n  return \u003CMemoizedChild style={style} \u002F>\n}\n\nconst MemoizedChild = React.memo(function Child({ style }) {\n  console.log('render') \u002F\u002F fires every render without useMemo above\n  return \u003Cdiv style={style}>hello\u003C\u002Fdiv>\n})\n```\n\nWithout referential stability, `React.memo` always sees \"new\" props,\n`useEffect` dependency checks always see \"new\" dependencies, and\ndownstream `useMemo`\u002F`useCallback` hooks always invalidate — making\nall memoisation downstream pointless.\n\n**Rule of thumb:** Stabilise object and array props with `useMemo`\nand function props with `useCallback` before passing them into\n`React.memo` components or `useEffect` dependencies.\n",{"id":42,"difficulty":14,"q":43,"a":44},"when-not-to-memoize","When should you NOT use useMemo or useCallback?","Memoisation has a **cost**: React must store the previous value, run\nthe dependency comparison on every render, and keep a closure alive\nin memory. For cheap operations, this overhead exceeds the saving.\n\n```jsx\n\u002F\u002F Bad — wrapping a trivial computation\nconst doubled = useMemo(() => count * 2, [count])\n\n\u002F\u002F Good — just compute it inline\nconst doubled = count * 2\n\n\u002F\u002F Bad — memoizing a callback that is never passed to a memo'd child\nconst handleClick = useCallback(() => setOpen(true), [])\n\n\u002F\u002F Good — inline is fine if the parent re-renders anyway\nconst handleClick = () => setOpen(true)\n```\n\nAvoid `useMemo`\u002F`useCallback` when:\n- The computation is fast (arithmetic, simple string ops)\n- The dependency changes on every render anyway\n- The child receiving the value is not wrapped in `React.memo`\n- You're in early development — premature optimisation obscures intent\n\n**Rule of thumb:** Profile first with React DevTools Profiler; add\nmemoisation only where you can measure a render-time win, not\npreemptively everywhere.\n",{"id":46,"difficulty":14,"q":47,"a":48},"expensive-computation-threshold","How do you decide if a computation is \"expensive enough\" to memoize?","There is no fixed rule, but the common benchmark is **>1 ms** in the\nprofiler during normal usage. React's own docs suggest a rough test:\nwrap the call in `console.time` \u002F `console.timeEnd` and see if it\nconsistently exceeds 1 ms on mid-range hardware.\n\n```jsx\n\u002F\u002F Quick check in development\nconsole.time('filter')\nconst result = hugeList.filter(expensivePredicate)\nconsole.timeEnd('filter') \u002F\u002F e.g. \"filter: 3.4 ms\" → worth memoizing\n\n\u002F\u002F Production pattern\nconst filtered = useMemo(\n  () => hugeList.filter(expensivePredicate),\n  [hugeList, expensivePredicate]\n)\n```\n\nCommon genuinely expensive operations: filtering\u002Fsorting large\narrays (10 000+ items), heavy string processing, recursive tree\ntraversals, and cryptographic hashes. Cheap operations that look\nexpensive but aren't: `.map` over \u003C500 items, simple arithmetic,\nand string concatenation.\n\n**Rule of thumb:** If `console.time` shows \u003C1 ms consistently, skip\n`useMemo` — the hook overhead may actually be slower than recomputing.\n",{"id":50,"difficulty":14,"q":51,"a":52},"usememo-with-react-memo","How do useMemo and React.memo work together?","`React.memo` skips re-rendering a child when **all props** are\nshallowly equal. For that to work, object and function props must\nbe referentially stable — which is exactly what `useMemo` and\n`useCallback` provide in the parent.\n\n```jsx\nconst Chart = React.memo(function Chart({ data, onHover }) {\n  console.log('Chart render')\n  return \u003Ccanvas \u002F> \u002F\u002F expensive canvas draw\n})\n\nfunction Dashboard({ rawData }) {\n  \u002F\u002F Without these, Chart re-renders on every Dashboard render\n  const data = useMemo(\n    () => transformForChart(rawData), \u002F\u002F stable reference\n    [rawData]\n  )\n  const onHover = useCallback(\n    (point) => showTooltip(point),\n    [] \u002F\u002F no deps — stable forever\n  )\n\n  return \u003CChart data={data} onHover={onHover} \u002F>\n}\n```\n\nThe three work as a unit: `React.memo` is the gate; `useMemo` and\n`useCallback` are what keep the keys from changing unnecessarily.\nWithout stable props, `React.memo` is effectively a no-op.\n\n**Rule of thumb:** Whenever you wrap a component in `React.memo`,\naudit its parent for inline objects\u002Ffunctions and stabilise them\nwith `useMemo`\u002F`useCallback`.\n",{"id":54,"difficulty":55,"q":56,"a":57},"stale-closures-in-callbacks","hard","What is a stale closure in useCallback and how do you fix it?","A **stale closure** occurs when a `useCallback` (or `useMemo`)\ncaptures a value from an earlier render because the dependency array\nwas incomplete. The function \"closes over\" the old value and continues\nusing it even after the real value has changed.\n\n```jsx\nfunction Counter() {\n  const [count, setCount] = useState(0)\n\n  \u002F\u002F BUG: count is captured at 0 and never updated\n  const logCount = useCallback(() => {\n    console.log(count) \u002F\u002F always logs 0\n  }, []) \u002F\u002F ← missing `count` dependency\n\n  \u002F\u002F FIX 1: add count to deps (new function ref when count changes)\n  const logCount = useCallback(() => {\n    console.log(count)\n  }, [count])\n\n  \u002F\u002F FIX 2: use functional updater when only setting state\n  const increment = useCallback(() => {\n    setCount(prev => prev + 1) \u002F\u002F no stale closure — reads latest\n  }, [])\n\n  return \u003Cbutton onClick={logCount}>Log {count}\u003C\u002Fbutton>\n}\n```\n\nThe ESLint `exhaustive-deps` rule catches most stale closures at\nlint time. For callbacks that need to always read the latest value\nwithout changing reference, consider the **ref-callback pattern**:\nstore the latest function in a ref and call it from a stable wrapper.\n\n**Rule of thumb:** Never omit a dependency to \"keep the function\nstable\" — either add it honestly or use `useReducer` \u002F functional\nupdates to remove the dependency legitimately.\n",{"id":59,"difficulty":14,"q":60,"a":61},"object-memoization-patterns","What are the common patterns for memoizing objects and derived data?","Three situations call for object memoisation:\n\n1. **Derived data** — transform props into a new object for rendering\n2. **Config objects** — pass stable option bags to child components\n3. **Context values** — prevent all consumers from re-rendering\n\n```jsx\nfunction UserCard({ user, theme }) {\n  \u002F\u002F 1. Derived data\n  const displayName = useMemo(\n    () => `${user.firstName} ${user.lastName}`.trim(),\n    [user.firstName, user.lastName]\n  )\n\n  \u002F\u002F 2. Stable config object for a memoized child\n  const chartOptions = useMemo(\n    () => ({ color: theme.primary, legend: false }),\n    [theme.primary]\n  )\n\n  \u002F\u002F 3. Context value — prevents all consumers re-rendering\n  const ctx = useMemo(\n    () => ({ user, displayName }),\n    [user, displayName]\n  )\n\n  return (\n    \u003CUserContext.Provider value={ctx}>\n      \u003CMemoizedChart options={chartOptions} \u002F>\n    \u003C\u002FUserContext.Provider>\n  )\n}\n```\n\nAvoid memoizing objects whose dependencies change on every render —\nyou get the cost of comparison with none of the saving.\n\n**Rule of thumb:** Memoize objects when you control neither the\nre-render frequency of the parent nor the comparison logic of the\nconsumer — context providers and `React.memo` children are the\ncanonical cases.\n",{"id":63,"difficulty":14,"q":64,"a":65},"inline-vs-extracted-callbacks","Should callbacks be inlined or extracted with useCallback?","The answer depends entirely on whether the callback is passed to a\n**memoized child** or used as a **`useEffect` dependency**.\n\n```jsx\nfunction Form() {\n  const [value, setValue] = useState('')\n\n  \u002F\u002F INLINE — fine: onChange is not passed to a memo'd child\n  \u002F\u002F and causes no extra effects\n  return (\n    \u003Cinput\n      onChange={e => setValue(e.target.value)} \u002F\u002F new ref each render\n      value={value}\n    \u002F>\n  )\n}\n\nfunction SearchPanel({ onSearch }) {\n  \u002F\u002F EXTRACTED — necessary: ResultList is React.memo'd\n  const handleSearch = useCallback(() => {\n    onSearch(query)\n  }, [onSearch, query])\n\n  return \u003CMemoizedResultList onSearch={handleSearch} \u002F>\n}\n```\n\nInline lambdas are idiomatic and readable for event handlers on\nDOM elements. Extracting with `useCallback` adds noise and overhead\nwhen the consumer doesn't benefit from a stable reference.\n\n**Rule of thumb:** Default to inline; extract with `useCallback`\nonly when the callback flows into a `React.memo` boundary or a\n`useEffect` \u002F `useMemo` dependency list.\n",{"id":67,"difficulty":55,"q":68,"a":69},"memoizing-callbacks-in-custom-hooks","Why should custom hooks wrap returned callbacks in useCallback?","A custom hook's returned functions become **dependencies** for any\n`useEffect` or `useCallback` in the consuming component. If the\nhook returns a new function reference on every call, the consumer\nis forced to either omit it from deps (stale closure risk) or accept\nspurious effect re-runs.\n\n```jsx\n\u002F\u002F Bad — new reference every render\nfunction useSearch(query) {\n  const search = () => fetchResults(query) \u002F\u002F new fn each time\n  return { search }\n}\n\n\u002F\u002F Good — stable reference, updates only when query changes\nfunction useSearch(query) {\n  const search = useCallback(\n    () => fetchResults(query),\n    [query]\n  )\n  return { search }\n}\n\n\u002F\u002F Consumer can now safely list `search` as a dep\nfunction SearchBox({ query }) {\n  const { search } = useSearch(query)\n\n  useEffect(() => {\n    search() \u002F\u002F no stale closure, no spurious re-runs\n  }, [search])\n}\n```\n\nThis is why popular hook libraries (React Query, SWR, Zustand)\nmemoize every returned function — it makes composition predictable\nwithout requiring callers to know the hook's internals.\n\n**Rule of thumb:** Treat functions returned from custom hooks the\nsame as public API — wrap them in `useCallback` so consumers can\nsafely include them in dependency arrays.\n",{"id":71,"difficulty":55,"q":72,"a":73},"usememo-context-rerenders","How can useMemo prevent unnecessary context consumer re-renders?","Every time a `Context.Provider` re-renders, **all consumers**\nre-render unless the context `value` is referentially the same\nobject. Without `useMemo`, a provider's value object is recreated\non every parent render, making the context update cascade\nunavoidable.\n\n```jsx\n\u002F\u002F Bad — new object on every Parent render\nfunction AuthProvider({ children }) {\n  const [user, setUser] = useState(null)\n  return (\n    \u003CAuthContext.Provider value={{ user, setUser }}>\n      {children}\n    \u003C\u002FAuthContext.Provider>\n  )\n}\n\n\u002F\u002F Good — stable object; consumers only re-render when user changes\nfunction AuthProvider({ children }) {\n  const [user, setUser] = useState(null)\n  const value = useMemo(\n    () => ({ user, setUser }),\n    [user] \u002F\u002F setUser is stable from useState, safe to omit\n  )\n  return (\n    \u003CAuthContext.Provider value={value}>\n      {children}\n    \u003C\u002FAuthContext.Provider>\n  )\n}\n```\n\nFor large apps, splitting context into a read context and a write\ncontext (each with its own `useMemo` value) further reduces\nre-renders: write-only consumers don't re-render when the user data\nchanges.\n\n**Rule of thumb:** Always wrap a context `value` in `useMemo` in\nproviders that live high in the tree — the blast radius of a\nneedless update is proportional to how many consumers are below it.\n",{"id":75,"difficulty":55,"q":76,"a":77},"memoization-correctness-pitfalls","What are the most common memoization correctness pitfalls in React?","Memoisation can introduce subtle bugs when the dependency array is\nwrong or when the memoized value is mutated instead of replaced.\n\n```jsx\n\u002F\u002F PITFALL 1: mutating the cached value\nconst items = useMemo(() => [], [])\nitems.push(newItem) \u002F\u002F ← mutates; useMemo won't notice, UI goes stale\n\n\u002F\u002F Fix: always return a new array\nconst items = useMemo(() => [...baseItems, newItem], [baseItems, newItem])\n\n\u002F\u002F PITFALL 2: object identity as a dep (always \"new\")\nconst options = { limit: 10 }\nconst result = useMemo(() => query(options), [options]) \u002F\u002F re-runs every render\n\n\u002F\u002F Fix: depend on primitives, not the object\nconst result = useMemo(() => query({ limit: 10 }), []) \u002F\u002F or [limit]\n\n\u002F\u002F PITFALL 3: async factory (useMemo is synchronous only)\nconst data = useMemo(async () => fetchData(), []) \u002F\u002F returns a Promise, not data\n\n\u002F\u002F Fix: use useEffect + useState for async work\n```\n\nThese pitfalls share a root cause: treating `useMemo` as smarter\nthan it is. It only tracks the dependency array — it cannot detect\nmutation or understand async semantics.\n\n**Rule of thumb:** Treat memoized values as **immutable**; never\nmutate them in place, depend only on primitives or already-stable\nreferences, and keep factory functions synchronous.\n",{"id":79,"difficulty":55,"q":80,"a":81},"ref-callback-pattern","What is the ref-callback pattern and when does it replace useCallback?","The **ref-callback pattern** (sometimes called \"latest ref\") keeps\na `useCallback` reference stable while still reading the latest\nclosure values. It solves the tension between \"stable function\" and\n\"always current data\".\n\n```jsx\nfunction useLatestCallback(fn) {\n  const ref = useRef(fn)\n  \u002F\u002F keep the ref up to date on every render (safe: layout effect)\n  useLayoutEffect(() => { ref.current = fn })\n  \u002F\u002F return a stable wrapper that delegates to the latest fn\n  return useCallback((...args) => ref.current(...args), [])\n}\n\nfunction SearchBox({ onSearch }) {\n  \u002F\u002F onSearch may change often, but handleSearch is always stable\n  const handleSearch = useLatestCallback(onSearch)\n\n  useEffect(() => {\n    const id = setInterval(handleSearch, 5000)\n    return () => clearInterval(id)\n  }, [handleSearch]) \u002F\u002F no stale closure, no interval reset on each render\n}\n```\n\nThis pattern is useful for event handlers and interval callbacks\nthat must be stable but need to capture the very latest state or\nprops. React's upcoming `useEffectEvent` hook formalises this\npattern in the framework itself.\n\n**Rule of thumb:** Reach for the ref-callback pattern when\n`useCallback` forces an awkward choice between adding a fast-moving\ndep (breaking stability) and omitting it (creating a stale closure).\n",{"id":83,"difficulty":14,"q":84,"a":85},"usecallback-with-event-handlers","Do event handlers on DOM elements need useCallback?","No. Native DOM event handlers (on `\u003Cbutton>`, `\u003Cinput>`, etc.) do\n**not** benefit from `useCallback`. React attaches DOM events at\nthe root via event delegation — the function reference you pass is\nnever directly stored on the DOM node, and changing it between\nrenders has zero cost.\n\n```jsx\nfunction Counter() {\n  const [count, setCount] = useState(0)\n\n  \u002F\u002F Unnecessary — the \u003Cbutton> doesn't care about reference stability\n  const handleClick = useCallback(\n    () => setCount(c => c + 1),\n    []\n  )\n\n  \u002F\u002F Equivalent and simpler\n  const handleClick = () => setCount(c => c + 1)\n\n  \u002F\u002F useCallback IS needed when handleClick flows into a memo'd child\n  return (\n    \u003C>\n      \u003Cbutton onClick={handleClick}>{count}\u003C\u002Fbutton>\n      \u003CMemoizedExpensiveChild onAction={handleClick} \u002F>\n    \u003C\u002F>\n  )\n}\n```\n\nThe second `\u003CMemoizedExpensiveChild>` case justifies `useCallback`\nbecause `React.memo`'s prop comparison is what creates the\nstability requirement — the DOM element does not.\n\n**Rule of thumb:** If the only consumer of a callback is a plain\nDOM element (not a `React.memo` component), skip `useCallback` —\nit adds complexity with no measurable benefit.\n",15,null,{"description":11},"React useMemo and useCallback interview questions — memoization patterns, dependency arrays, when to use each hook, referential stability, and common pitfalls.","react\u002Frendering-and-performance\u002Fusememo-usecallback-patterns","useMemo and useCallback Patterns","Rendering and Performance","rendering-and-performance","2026-06-24","qvgFVw09_MDmKpdnJo5Rk2LaOnMGjDsmC8vmk7xeLN4",[97,101,104,105,109],{"subtopic":98,"path":99,"order":100},"Virtual DOM and Reconciliation","\u002Freact\u002Frendering-and-performance\u002Fvirtual-dom-reconciliation",1,{"subtopic":102,"path":103,"order":12},"React.memo","\u002Freact\u002Frendering-and-performance\u002Freact-memo",{"subtopic":91,"path":22,"order":21},{"subtopic":106,"path":107,"order":108},"Code Splitting and Lazy Loading","\u002Freact\u002Frendering-and-performance\u002Fcode-splitting-lazy",4,{"subtopic":110,"path":111,"order":112},"Suspense and Concurrent Rendering","\u002Freact\u002Frendering-and-performance\u002Fsuspense-concurrent",5,{"path":114,"title":115},"\u002Fblog\u002Freact-usememo-usecallback-patterns-guide","React useMemo and useCallback Patterns — A Complete Guide",1782244101007]