React Tutorials: useMemo vs useCallback vs React.memo

Imagine a product list page:

  • You fetch 1000 products
  • You want to sort them
  • Each product is displayed in a ProductCard
  • Clicking a product adds it to a cart
  • Without optimization:
  • sorting runs every render
  • functions change every render
  • product cards re-render unnecessarily

 

We optimize using:

  • useMemo
  • useCallback
  • React.memo

1. Product Page (Main Component)

				
					"use client"

import { useState, useMemo, useCallback } from "react"
import ProductCard from "./ProductCard"

export default function ProductsPage() {
  const [cart, setCart] = useState([])
  const [products] = useState([
    { id: 1, name: "Keyboard", price: 500 },
    { id: 2, name: "Mouse", price: 200 },
    { id: 3, name: "Monitor", price: 2000 }
  ])

  // useMemo example
  const sortedProducts = useMemo(() => {
    console.log("Sorting products...")
    return [...products].sort((a, b) => a.price - b.price)
  }, [products])

  // useCallback example
  const addToCart = useCallback((product) => {
    setCart(prev => [...prev, product])
  }, [])

  return (
    <div>
      <h1>Products</h1>

      {sortedProducts.map(product => (
        <ProductCard
          key={product.id}
          product={product}
          onAddToCart={addToCart}
        />
      ))}
    </div>
  )
}
				
			

2. Product Card Component

Here we use React.memo

				
					import React from "react"

const ProductCard = React.memo(({ product, onAddToCart }) => {
  console.log("Rendering:", product.name)

  return (
    <div>
      <h3>{product.name}</h3>
      <p>R{product.price}</p>

      <button onClick={() => onAddToCart(product)}>
        Add to Cart
      </button>
    </div>
  )
})

export default ProductCard
				
			

What each optimization does

1️⃣ useMemo (Memoizing Values)

				
					const sortedProducts = useMemo(() => {
  return [...products].sort((a, b) => a.price - b.price)
}, [products])
				
			

Without useMemo:

  • sorting runs every render

 

With useMemo:

  • sorting runs only if products change

 

Good for:

  • sorting
  • filtering
  • expensive calculations

2️⃣ useCallback (Memoizing Functions)

				
					const addToCart = useCallback((product) => {
  setCart(prev => [...prev, product])
}, [])
				
			

Without useCallback:

Every render creates a new function reference

				
					const addToCart = (product) => { ... }
				
			

That causes child components to re-render.

With useCallback:

  • same function reference
  • fewer child re-renders

3️⃣ React.memo (Memoizing Components)

				
					const ProductCard = React.memo(({ product }) => {
				
			

React will skip rendering this component if props didn’t change.

Without it:

  • every product card re-renders whenever parent renders.

With it:

  • only cards with changed props re-render.

What happens without optimization?

❌ Products re-sort
❌ addToCart function recreated
❌ All product cards re-render

What happens With optimization?

✅ sorting does NOT run again (useMemo)
✅ function reference stays same (useCallback)
✅ product cards do NOT re-render (React.memo)

useMemo memoizes computed values, useCallback memoizes functions to prevent new references, and React.memo memoizes components so they only re-render when their props change.

Get in touch with us!

Ready to bring your digital vision to life? Drop us a message, and our expert team will get back to you to discuss how we can turn your ideas into reality. Let’s create something amazing together!

Explore how we can help you succeed. Check out our full range of services now!