Нужно ли использовать useMemo или useRef для хранения статичных данных в React?
Что проверяют
Различаете ли вы «значение не должно пересчитываться» и «ячейка должна пережить рендер», и знаете ли, что useMemo это подсказка движку, а не контракт.
Как отвечать
Начать стоит с того, что для по-настоящему статичных данных хук не нужен вовсе. Константа, не зависящая ни от пропсов, ни от состояния, выносится за пределы компонента: она создаётся один раз на модуль, не занимает слот хука и не участвует в сравнении зависимостей.
useMemo: производное значение, которое считается из пропсов или состояния и стоит дороже, чем сравнение зависимостей.useRef: изменяемая ячейка, которая переживает рендеры и не вызывает перерисовку при записи. Сюда же идут таймеры, идентификаторы подписок, предыдущее значение.
const COLUMNS = [{ key: "name" }]; // статика живёт вне компонента
const ref = useRef(null);
if (ref.current === null) ref.current = createHeavyThing();Важная деталь: useRef(createHeavyThing()) вычисляет аргумент на каждом рендере и почти всегда выбрасывает результат, поэтому дорогое создание оборачивают проверкой на null или отдают ленивому инициализатору useState. И отдельно: React вправе выбросить кэш useMemo, так что на нём нельзя строить логику, где значение обязано остаться тем же объектом.
Где спотыкаются
Используют useMemo с пустым списком зависимостей как способ создать значение ровно один раз и строят на этом идентичность объекта: ключ подписки, идентификатор, ячейку кэша. Это оптимизация, а не обещание.
Читают и пишут ref.current во время рендера. Рендер обязан быть чистым, иначе компонент увидит значение от прохода, который React выбросил. Обращаться к ссылке можно в обработчиках и эффектах.
Ставят ref.current в список зависимостей useMemo, надеясь на пересчёт. Изменение ссылки не вызывает ни рендера, ни пересчёта, так что зависимость остаётся декоративной, а значение устаревает.