Both useMemo and useCallback are optimization hooks that cache values between renders to prevent performance regressions, but they target different data types:
1. useMemo caches the *result* of a calculation. It executes a function and remembers its return value. It only recalculates when dependencies change.
const heavyCalculationValue = useMemo(() => {
return expensiveCompute(data);
}, [data]);
2. useCallback caches the *function instance* itself. It returns the exact same function reference across renders instead of recreating it, preventing child components that receive the function as a prop from unnecessarily re-rendering.
const handleToggle = useCallback(() => {
setOpen(prev => !prev);
}, []);
Both hooks have a memory overhead because they must keep references to dependencies and past computations in memory. Overusing them for simple computations can actually *hurt* performance. Use them when passing callbacks to memoized children (React.memo) or when dependencies trigger expensive downstream effects.