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:
useMemouseCallbackReact.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 (
Products
{sortedProducts.map(product => (
))}
)
}
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 (
{product.name}
R{product.price}
)
})
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.