← Назад к вопросам

Что такое useMallback?

2.0 Middle🔥 161 комментариев
#JavaScript Core

Комментарии (1)

🐱
deepseek-v3.2PrepBro AI6 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Что такое useMemo и useCallback в React?

В контексте React и его хуков, часто возникает вопрос о useCallback. Однако, ваш вопрос содержит термин useMallback, который не является официальным хуком React. Я предполагаю, что это либо опечатка, либо неформальное объединение концепций useMemo и useCallback, которые часто используются вместе для оптимизации. Давайте подробно разберем оба этих ключевых хука для управления мемоизацией (Memoization).

Основная концепция: Мемоизация

Мемоизация — это техника оптимизации, которая заключается в сохранении результатов выполнения функций для избежания повторных вычислений при одинаковых входных данных. В React это критически важно для предотвращения ненужных ререндеров компонентов и создания новых объектов/функций.

React предоставляет два хука для этой цели:

  • useMemo — мемоизирует значение (результат вычисления).
  • useCallback — мемоизирует саму функцию.

Хук useMemo

useMemo используется для сохранения (мемоизации) вычисленного значения между рендерами. Он принимает функцию-создатель и массив зависимостей. Значение будет пересчитано только при изменении одной из зависимостей.

import React, { useMemo } from 'react';

function ExpensiveComponent({ list }) {
  // Мемоизируем результат сложной операции сортировки/фильтрации
  const sortedList = useMemo(() => {
    console.log('Вычисление sortedList...');
    return list.sort((a, b) => a.value - b.value);
  }, [list]); // Пересчитываем только если массив `list` изменился

  return <div>{sortedList.map(item => <p key={item.id}>{item.value}</p>)}</div>;
}

Ключевое применение: избежание дорогостоящих вычислений (фильтрация, сортировка, агрегация данных) на каждом рендере.

Хук useCallback

useCallback используется для мемоизации функции между рендерами. Как и useMemo, он принимает функцию и массив зависимостей. Он возвращает ту же самую функцию, если зависимости не изменились.

import React, { useCallback, useState } from 'react';

function ParentComponent() {
  const [count, setCount] = useState(0);

  // Мемоизированная функция обработчика события
  const handleClick = useCallback(() => {
    setCount(prev => prev + 1);
  }, []); // Зависимости пусты - функция никогда не меняется

  // Другая мемоизированная функция, зависящая от состояния
  const handleReset = useCallback(() => {
    setCount(0);
  }, [setCount]); // setCount стабилен, но формально указан как зависимость

  return (
    <div>
      <ChildComponent onClick={handleClick} />
      <button onClick={handleReset}>Reset</button>
      <p>Count: {count}</p>
    </div>
  );
}

function ChildComponent({ onClick }) {
  // Этот компонент может зависеть от стабильности пропса `onClick`
  // для своих оптимизаций (например, если он обернут в React.memo)
  return <button onClick={onClick}>Increment from Child</button>;
}

Ключевое применение: предотвращение создания новых функций на каждом рендере, что важно когда:

  1. Функция передается как проп в оптимизированный child-компонент (обернутый в React.memo). Новый пропс каждый рендер вызовет ререндер child-компонента.
  2. Функция используется как зависимость в других хуках (например, useEffect). Если функция меняется каждый рендер, эффект будет запускаться слишком часто.
useEffect(() => {
  // Этот эффект будет запускаться только если `fetchData` изменится
  fetchData();
}, [fetchData]);

Сравнение useMemo и useCallback

ОсобенностьuseMemouseCallback
Что возвращаетМемоизированное значение (результат вычисления)Мемоизированная функция (сама функция-объект)
Основная цельОптимизация дорогостоящих вычисленийОптимизация передачи функций как пропсов и зависимостей
Пример использованияconst value = useMemo(() => compute(a, b), [a, b]);const fn = useCallback(() => doSomething(a, b), [a, b]);

Внутренняя реализация и важные предостережения

Оба хука имеют схожую внутреннюю логику. React хранит предыдущее значение/функцию и массив зависимостей. На каждом рендере он сравнивает текущие зависимости с предыдущими (используя примерно Object.is для каждого элемента). Если они одинаковы — возвращается сохраненное значение/функция. Если нет — вычисляется новое и сохраняется.

Важно помнить:

  • Не используйте эти хуки для каждой функции или вычисления. Избыточное применение может снизить производительность из-за накладных расходов на сравнение зависимостей и усложнить код.
  • Мемоизация не предотвращает создание функций внутри useMemo. useMemo(() => () => {...}, []) создает новую функцию каждый раз при пересчете, но возвращает ее как значение. Для мемоизации функции используйте именно useCallback.
  • Они не являются гарантией сохранения ссылки. Если зависимости меняются, ссылка на объект/функцию тоже меняется.
  • Основная выгода проявляется в сочетании с другими оптимизациями, такими как React.memo для компонентов или при работе с большими списками и эффектами.

Заключение

Таким образом, useMallback — вероятно, неформальное объединение терминов useMemo и useCallback, двух фундаментальных хуков React для оптимизации через мемоизацию. Их правильное применение требует понимания:

  1. Работы с зависимостями (dependency arrays).
  2. Принципов ререндеров React и того, как новые ссылки на объекты/функции влияют на них.
  3. Контекста использованияuseMemo для значений, useCallback для функций.

Эти инструменты являются частью стратегии performance optimization в React, помогая избежать ненужных вычислений и ререндеров в критических частях приложения. Однако, их следует применять обдуманно, основываясь на реальных измерениях производительности (например, с помощью React Profiler), а не на предположениях.