The useCallback hook returns a memoized version of a callback function that only changes when one of its specified dependencies changes.
In JavaScript, functions are first-class objects. Every time a component re-renders, any inline arrow functions or callback definitions inside its body are recreated with new memory references. Passing un-memoized callbacks to memoized child components (React.memo) breaks shallow comparison and causes unwanted child re-renders.
flowchart TD
Parent["Parent Re-renders"] --> Check{"Have Dependencies Changed?"}
Check -- No --> Keep["Return Cached Function Reference"]
Check -- Yes --> Recreate["Re-create New Function Reference"]
import React, { useState, useCallback, memo } from 'react';
// Child component memoized with React.memo
const FilterButton = memo(({ category, onClick }) => {
console.log(`FilterButton [${category}] rendered!`);
return (
<button onClick={() => onClick(category)} className="btn">
Filter by {category}
</button>
);
});
export default function ProductCatalog() {
const [selectedCategory, setSelectedCategory] = useState('All');
const [searchTerm, setSearchTerm] = useState('');
// useCallback memoizes function reference across renders
const handleCategorySelect = useCallback((category) => {
setSelectedCategory(category);
}, []); // Empty dependency array: Function reference remains identical forever
return (
<div className="catalog">
<h2>Selected: {selectedCategory}</h2>
{/* Typing in search updates search state, but FilterButton will NOT re-render */}
<input
type="text"
value={searchTerm}
onChange={(e) => setSearchTerm(e.target.value)}
placeholder="Type to search..."
/>
<div className="button-group">
<FilterButton category="Electronics" onClick={handleCategorySelect} />
<FilterButton category="Books" onClick={handleCategorySelect} />
</div>
</div>
);
}
useCallback with React.memo: Using useCallback by itself on a function passed to an unmemoized native element (<button onClick={fn}>) provides zero rendering optimization. Use useCallback primarily when passing callbacks to React.memo components or useEffect dependencies.Explain why useCallback(fn, deps) is equivalent to useMemo(() => fn, deps).
Sign in to track your learning journey, earn industry-recognized certificates, and join our elite developer community.
Quick Access With
You've completed this section! Take a quick 5-question quiz to check your understanding.