PassFront
  1. PassFront
  2. База знаний
  3. Хуки

В чем разница между useMemo и useEffect?

Хуки

Оба принимают колбэк и зависимости, но делают противоположное: useMemo вычисляет значение во время рендера, useEffect выполняет побочный код после рендера.

Суть каждого

// useMemo: СИНХРОННО вычислить и закешировать ЗНАЧЕНИЕ для рендера
const visible = useMemo(
  () => items.filter((i) => i.status === filter),
  [items, filter],
);

// useEffect: ПОСЛЕ рендера выполнить ПОБОЧНЫЙ ЭФФЕКТ
useEffect(() => {
  analytics.track('filter_changed', { filter });
}, [filter]);

Отличия

  • Время выполнения: useMemo — во время рендера, синхронно (результат нужен для JSX прямо сейчас); useEffect — после коммита и отрисовки.
  • Возврат: useMemo возвращает значение, используемое в рендере; useEffect ничего не возвращает (кроме cleanup-функции).
  • Чистота: колбэк useMemo обязан быть чистым (никаких запросов, подписок, setState); useEffect существует именно для «грязной» работы.
  • Cleanup: есть только у useEffect.
  • Назначение: оптимизация вычислений против синхронизации с внешним миром.

Типовая ошибка — путать их роли

// ❌ производное значение через effect + state: лишний цикл рендера
const [visible, setVisible] = useState([]);
useEffect(() => { setVisible(items.filter(f)); }, [items]);

// ✅ производное значение — это вычисление: useMemo (или просто в рендере)
const visible = useMemo(() => items.filter(f), [items]);

И наоборот: запрос данных в useMemo — нарушение чистоты рендера; место запросам — в эффекте (или React Query).

Коротко для собеседования

useMemo — синхронное кеширование вычисленного значения для рендера (чистая функция); useEffect — побочные эффекты после рендера (запросы, подписки, DOM) с cleanup. Правило: производные данные — useMemo, взаимодействие с внешним миром — useEffect; подмена одного другим — распространённый антипаттерн.

Другие вопросы раздела