> Нужно ли использовать useMemo или useRef для хранения статичных данных в React? (React)

Уровень: senior · Роль: frontend · Категория: Технические вопросы

Компании: Альфа-банк

Стек: React

> Пример ответа

Короткий ответ

Для хранения статичных данных в React предпочтительнее использовать useRef, а не useMemo. useMemo предназначен для мемоизации результатов дорогостоящих вычислений и может быть вызван повторно при изменении зависимостей. useRef создаёт объект, который сохраняется на всё время жизни компонента, не имеет зависимостей и не участвует в рендеринге. Для неизменяемых значений, которые не требуют вычислений, useRef - правильный и более производительный выбор.

Подробное объяснение

Разница между useMemo и useRef для статичных данных принципиальна. useMemo - это хук для мемоизации, который:

  • Вычисляет значение при первом рендере
  • Пересчитывает его при изменении зависимостей (даже если они пусты - только один раз)
  • Возвращает результат вычисления
  • Может быть оптимизирован компилятором (React может отбросить мемоизацию при отсутствии профита)

useRef же:

  • Создаёт объект { current: initialValue } один раз при монтировании
  • Не имеет зависимостей
  • Не вызывает повторных вычислений
  • Не участвует в процессе рендеринга (изменение ref.current не вызывает ререндер)

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

  1. React может в будущих версиях изменить поведение useMemo
  2. useMemo подразумевает, что вычисление может быть повторено - это семантически неверно для статичных данных
  3. useRef не требует зависимостей, что делает код чище

На практике

В реальных проектах статичные данные часто выносят за пределы компонента - в константы модуля или отдельные файлы. Это самый простой и эффективный способ. Если же данные должны быть привязаны к конкретному экземпляру компонента (например, уникальный ID или экземпляр класса), используйте useRef.

Примеры статичных данных, где useRef уместен:

  • Уникальный идентификатор компонента (uuid)
  • Ссылка на DOM-элемент
  • Экземпляр сторонней библиотеки (карта, график)
  • Callback-функция, которая не должна меняться (но для этого лучше useCallback)
  • Объект с конфигурацией, специфичной для экземпляра

useMemo для статичных данных - это антипаттерн, который может запутать других разработчиков и создать ложное впечатление о наличии дорогостоящих вычислений.

Пример кода

JSX
// ❌ Плохо: useMemo для статичных данных
function Component() {
const staticData = useMemo(() => ({
id: generateUUID(),
createdAt: Date.now(),
config: { theme: 'dark', lang: 'ru' }
}), []); // пустой массив - костыль
}
// ✅ Хорошо: useRef для статичных данных экземпляра
function Component() {
const instanceData = useRef({
id: generateUUID(),
createdAt: Date.now(),
config: { theme: 'dark', lang: 'ru' }
}).current;
}
// ✅ Лучше всего: константа вне компонента
const DEFAULT_CONFIG = { theme: 'dark', lang: 'ru' };
function Component() {
// используем DEFAULT_CONFIG напрямую
}

Как отвечать на собеседовании

Начните с чёткого разграничения назначения хуков: useRef для ссылок и стабильных объектов, useMemo для мемоизации вычислений. Объясните, почему useMemo с пустыми зависимостями - это неправильное использование: семантически неверно, может ввести в заблуждение, не даёт преимуществ перед useRef. Упомяните, что в большинстве случаев статичные данные лучше выносить за пределы компонента. Подчеркните, что useRef не вызывает ререндеров и не имеет зависимостей, что делает его идеальным для статичных данных экземпляра.

Что проверяет интервьюер

Интервьюер оценивает:

  • Понимание семантики хуков React (useRef vs useMemo)
  • Знание механизмов рендеринга и мемоизации
  • Умение выбирать правильный инструмент под задачу
  • Понимание trade-off между производительностью и читаемостью кода
  • Способность объяснить разницу между "вычисляется один раз" и "создаётся один раз"

Типичные ошибки

  • Использование useMemo с пустыми зависимостями для статичных данных - семантически неверно
  • Забывают, что useRef возвращает объект, а не значение - нужно обращаться через .current
  • Пытаются хранить в useRef данные, которые должны обновляться и влиять на UI - для этого нужен useState
  • Создают статичные данные внутри компонента, хотя их можно вынести наружу
  • Путают useRef с createRef - createRef создаёт новый объект при каждом рендере

> ГОТОВЫ К СЛЕДУЮЩЕМУ СОБЕСЕДОВАНИЮ?

Запустите тренировочную сессию с ИИ и получите детальную обратную связь, чтобы увереннее проходить реальные интервью