Какие проблемы решает useMemo?
Хуки
useMemo решает две разные проблемы: дорогие повторные вычисления и нестабильные ссылки.
Проблема 1: пересчёт на каждом рендере
Тело компонента выполняется при каждом рендере — вместе с ним и тяжёлые вычисления, даже если исходные данные не менялись:
const Report = ({ rows, filter }) => {
// без useMemo: сортировка 10 000 строк на КАЖДЫЙ рендер,
// включая ввод в несвязанное поле
const sorted = useMemo(
() => [...rows].filter((r) => r.type === filter).sort(byDate),
[rows, filter],
);
};Выигрыш реален только когда вычисление действительно дорогое: для a + b useMemo вреден (сравнение deps дороже).
Проблема 2: новая ссылка каждый рендер
Объекты и массивы, создаваемые в рендере, каждый раз новые. Это ломает всё, что сравнивает по ссылке:
const config = useMemo(() => ({ pageSize: 20 }), []);
<Table config={config} /> // React.memo(Table) теперь работает
useEffect(() => load(config), [config]); // эффект не перезапускается каждый рендерЗдесь useMemo нужен не ради скорости вычисления (объект создаётся мгновенно), а ради стабильности ссылки для memo-детей и зависимостей хуков.
Чего useMemo не решает
Не убирает сам ререндер компонента (это React.memo), не гарантирует однократное выполнение (React вправе сбросить кеш), не место для побочных эффектов. И не нужен там, где вычисление дёшево — лишняя сложность.
Коротко для собеседования
useMemo решает: (1) повторные дорогие вычисления — результат кешируется до изменения deps; (2) нестабильные ссылки на объекты/массивы — чтобы не ломать React.memo у детей и зависимости эффектов. Не убирает ререндер, не гарантирует однократность и не нужен для дешёвых вычислений.