Memoization in React with useMemo and useCallback

Maya Patel Jan 2026
1 tab
import { useState, useMemo, useCallback } from 'react'
import { Post } from '@/types'
import { PostCard } from './PostCard'

interface FilteredPostsProps {
  posts: Post[]
}

export function FilteredPosts({ posts }: FilteredPostsProps) {
  const [searchTerm, setSearchTerm] = useState('')
  const [category, setCategory] = useState<string | null>(null)

  // Memoize expensive filtering operation
  const filteredPosts = useMemo(() => {
    return posts.filter((post) => {
      const matchesSearch = post.title.toLowerCase().includes(searchTerm.toLowerCase())
      const matchesCategory = !category || post.category === category
      return matchesSearch && matchesCategory
    })
  }, [posts, searchTerm, category])

  // Memoize sorted result
  const sortedPosts = useMemo(() => {
    return [...filteredPosts].sort((a, b) =>
      b.published_at.localeCompare(a.published_at)
    )
  }, [filteredPosts])

  // Memoize callback to prevent child re-renders
  const handleLike = useCallback((postId: string) => {
    // Handle like action
    console.log('Liked post:', postId)
  }, [])

  return (
    <div>
      <div className="mb-4 flex gap-4">
        <input
          type="search"
          value={searchTerm}
          onChange={(e) => setSearchTerm(e.target.value)}
          placeholder="Search posts..."
          className="px-3 py-2 border rounded"
        />
        <select
          value={category || ''}
          onChange={(e) => setCategory(e.target.value || null)}
          className="px-3 py-2 border rounded"
        >
          <option value="">All Categories</option>
          <option value="tech">Tech</option>
          <option value="design">Design</option>
        </select>
      </div>

      <div className="text-sm text-gray-600 mb-4">
        Showing {sortedPosts.length} of {posts.length} posts
      </div>

      <div className="space-y-4">
        {sortedPosts.map((post) => (
          <PostCard key={post.id} post={post} onLike={handleLike} />
        ))}
      </div>
    </div>
  )
}
1 file · typescript Explain with highlit

Unnecessary re-renders hurt performance, especially with expensive computations or callbacks passed to child components. useMemo memoizes computed values, recalculating only when dependencies change. useCallback memoizes function instances, preventing child re-renders when functions are passed as props. I use useMemo for filtering/sorting large arrays or expensive calculations. useCallback stabilizes event handlers passed to memoized children. The dependencies array is critical—omitting dependencies causes stale closures, while over-specifying causes unnecessary recalculations. React DevTools Profiler identifies components that benefit from memoization. The key is balancing optimization with complexity—premature optimization adds cognitive overhead without measurable gains.