React useCallback
Memoize function references to optimize child re-renders
Overview
useCallback returns a stable function reference between renders when dependencies are unchanged. It helps React.memo children avoid re-rendering because a new inline function was passed as a prop.
Syntax / Usage
import { useCallback, useState, memo } from 'react'
const ListItem = memo(function ListItem({ item, onSelect }) {
return (
<button onClick={() => onSelect(item.id)}>
{item.name}
</button>
)
})
function ItemList({ items }) {
const [selected, setSelected] = useState(null)
const handleSelect = useCallback((id) => {
setSelected(id)
}, [])
return items.map((item) => (
<ListItem key={item.id} item={item} onSelect={handleSelect} />
))
}
useCallback(fn, deps) is equivalent to useMemo(() => fn, deps).
Examples
Pass stable handler to a virtualized list:
const onRowClick = useCallback((rowIndex) => {
setActiveRow(rowIndex)
}, [])
Debounce wrapper with stable identity:
const debouncedSearch = useCallback(
debounce((term) => fetchResults(term), 300),
[] // debounce instance created once
)
Common Mistakes
- Wrapping every function in
useCallbackwithout a memoized child—adds cost, no benefit - Stale closures from incomplete dependency arrays
- Assuming
useCallbackprevents the function body from running—it only stabilizes the reference - Pairing with
React.memoon children but passing unstable object props
See Also
use-memo use-effect props components