useMemo & Computed Values

Med

useMemo caches the result of an expensive computation between re-renders, recomputing only when its dependencies change. It prevents unnecessary recalculations and maintains referential stability for objects and arrays passed as props or used in dependency arrays.

Interactive Visualization

Key Points

  • Accepts a function and dependency array, returns the memoized result
  • Only recomputes when a dependency changes (shallow comparison)
  • Primary use: skip expensive recalculations like sorting or filtering large lists
  • Secondary use: maintain stable object/array references for React.memo or effect dependencies
  • Not free: has overhead from dependency comparison and memory for cached values
  • React may drop the cache in the future, so code must work without it

Code Examples

Expensive Computation

import { useMemo, useState } from 'react'

interface Product {
  id: string
  name: string
  price: number
  category: string
}

function ProductList({ products }: { products: Product[] }) {
  const [filter, setFilter] = useState('')
  const [sortBy, setSortBy] = useState<'name' | 'price'>('name')

  const filteredAndSorted = useMemo(() => {
    const filtered = products.filter((p) =>
      p.name.toLowerCase().includes(filter.toLowerCase())
    )
    return filtered.sort((a, b) =>
      sortBy === 'price'
        ? a.price - b.price
        : a.name.localeCompare(b.name)
    )
  }, [products, filter, sortBy])

  return (
    <div>
      <input value={filter} onChange={(e) => setFilter(e.target.value)} />
      <button onClick={() => setSortBy('price')}>Sort by Price</button>
      {filteredAndSorted.map((p) => (
        <div key={p.id}>{p.name}: ${p.price}</div>
      ))}
    </div>
  )
}

Filtering and sorting only recompute when products, filter, or sortBy change, not on every render from unrelated state updates

Stable Reference for Child Components

import { useMemo } from 'react'

interface ChartData {
  labels: string[]
  values: number[]
}

interface DashboardProps {
  revenue: number[]
  months: string[]
}

function Dashboard({ revenue, months }: DashboardProps) {
  // Without useMemo, this creates a new object every render,
  // causing MemoizedChart to re-render unnecessarily
  const chartData: ChartData = useMemo(
    () => ({ labels: months, values: revenue }),
    [months, revenue]
  )

  return <MemoizedChart data={chartData} />
}

useMemo keeps the same object reference between renders so memoized children can skip re-rendering via shallow prop comparison

Common Mistakes

  • Wrapping every computation in useMemo even when the cost is trivial
  • Omitting dependencies or including stale references in the dependency array
  • Using useMemo where useCallback is more appropriate for memoizing functions

Interview Tips

  • Explain that useMemo is an optimization, not a semantic guarantee
  • Discuss when NOT to use useMemo: simple calculations, primitive values, rarely changing data
  • Know that React may drop memoized values in the future to free memory

Related Concepts