Have you ever noticed your application stuttering when you switch categories or type in a search box?
This is a classic symptom of unnecessary re-renders in React.
For dynamic lists, especially product catalogs, a little bit of optimization goes a long way.
We’ll use a real-world code example to show you the powerful combination of two React tools—useMemo and React.memo—to keep your UI snappy and fast.
🛠️ The Problem: Wasted Work in React
In React, when a parent component re-renders (e.g., when a state updates), all its child components also re-render by default. This is usually fine, but when you have a list with hundreds of items, forcing every single item to update, even if its data hasn’t changed, is a massive waste of CPU cycles.
Our goal is to create optimization barriers to prevent this wasted work.
🚀 Solution 1: Memoize Expensive Calculations with useMemo
The most common source of lag in a product list is the data processing itself—things like filtering and sorting. We don’t want to re-filter our massive product list every time an unrelated piece of state changes (like a simple search input).
The Fix in OptimizedProductList
We use the useMemo hook to create a stable reference to our filtered product list.
// --- Main Optimized Component (Excerpt) ---
function OptimizedProductList() {
const [activeCategory, setActiveCategory] = useState('Electronics');
const [searchText, setSearchText] = useState('');
// 💡 Optimization: useMemo filters the products ONLY when 'activeCategory' changes.
const filteredProducts = useMemo(() => {
console.log('*** FILTERING PRODUCTS (Only runs when category changes) ***');
return ALL_PRODUCTS.filter(p => p.category === activeCategory);
}, [activeCategory]); // Dependency Array: Only re-run when activeCategory changes.
// ... rest of the component
}
- How it Works: The filter function runs only when a dependency in the array (
activeCategory) changes. - The Benefit: If the user starts typing in the
searchTextinput, theOptimizedProductListcomponent re-renders, but the filtering function insideuseMemois skipped entirely. This saves significant calculation time.
🎯 Solution 2: Prevent Child Re-renders with React.memo
While useMemo prevents re-calculating the list, we still have to prevent the individual product cards from re-rendering when the parent updates. This is where React.memo comes in.
The Fix on ProductCard
We wrap our ProductCard functional component with React.memo.
// --- ProductCard Component ---
// 💡 Optimization: React.memo prevents re-render unless its 'product' prop changes.
const ProductCard = React.memo(({ product }) => {
// Console log to observe re-renders
console.log(`Rendering Product: ${product.name}`);
// ... JSX for the card
});
- How it Works:
React.memois a Higher-Order Component (HOC) that automatically compares the component’s props between renders. - The Benefit: When the user types in the
searchTextfield, the parent component re-renders, but thefilteredProductsarray reference passed to the list is the same (thanks touseMemo). Since the props for eachProductCardhaven’t changed,React.memotells React to skip rendering that component, avoiding hundreds of needless updates.
📈 The Final, Optimized Code in Action
By combining these two techniques, we create an optimized component that only performs work when the data that affects the list actually changes.
// Complete Optimized Code
function OptimizedProductList() {
const [activeCategory, setActiveCategory] = useState('Electronics');
const [searchText, setSearchText] = useState('');
// 1. Data Filtering (useMemo)
const filteredProducts = useMemo(() => {
console.log('*** FILTERING PRODUCTS (Only runs when category changes) ***');
return ALL_PRODUCTS.filter(p => p.category === activeCategory);
}, [activeCategory]);
// ... rest of the component
return (
<div>
{/* ... Filter/Search UI */}
<input
value={searchText}
onChange={(e) => setSearchText(e.target.value)}
placeholder="Type to cause a parent re-render..."
/>
<p>Parent component re-rendered ({searchText})</p>
<hr />
<div className="product-list">
{/* 2. List Rendering (ProductCard is wrapped in React.memo) */}
{filteredProducts.map(product => (
<ProductCard key={product.id} product={product} />
))}
</div>
</div>
);
}
Try It: With this setup, typing in the search bar only causes the parent to update the searchText counter. It does not trigger the *** FILTERING PRODUCTS *** console log, and more importantly, it does not trigger the Rendering Product: log for the child components!
Your product list is now fast, efficient, and ready for your next e-commerce feature!
Useful links below:
Let me & my team build you a money making website/blog for your business https://bit.ly/tnrwebsite_service
Get Bluehost hosting for as little as $1.99/month (save 75%)…https://bit.ly/3C1fZd2
Join my Patreon for one-on-one coaching and help with your coding…https://www.patreon.com/c/TyronneRatcliff
Buy me a coffee https://buymeacoffee.com/tyronneratcliff



