Оба кэшируют что-то между рендерами, чтобы это не пересчитывалось/не пересоздавалось каждый раз:
useMemoкэширует .
Оба кэшируют что-то между рендерами, чтобы это не пересчитывалось/не пересоздавалось каждый раз:
useMemo кэширует .useCallback кэширует идентичность функции (это useMemo(() => fn, deps)).Они существуют для того, чтобы избежать (a) повторения дорогостоящей работы и (b) нарушения равенства ссылок, от которого зависят мемоизированные дочерние компоненты.
function Table({ rows, onSelect }) {
// (a) expensive computation — recompute only when `rows` changes
const sorted = useMemo(() => rows.slice().sort(byName), [rows]);
// (b) stable function identity — so a React.memo child doesn't re-render,
// and effects depending on it don't re-fire
const handleSelect = useCallback(id => onSelect(id), [onSelect]);
return <Grid rows={sorted} onSelect={handleSelect} />;
}
Без useCallback, handleSelect — это совершенно новая функция при каждом рендере. React.memo(Grid) увидит «новый» пропс и все равно отрендерится, нарушив мемоизацию. То же самое касается объекта, передаваемого мемоизированному потомку, или используемого в массиве зависимостей useEffect.
const x = useMemo(() => a + b, [a, b]); // ❌ pointless — adding is cheaper than memoizing
useMemo/useCallback везде добавляет шума и может быть даже медленнее. (Компилятор React 19 может автоматически мемоизировать, снижая необходимость.)