Можно ли хранить данные в refs, которые не вызывают повторный рендер
Что проверяют
Отличаете ли вы состояние от просто изменяемой ячейки. useRef любят называть «состоянием без рендера», и по ответу сразу видно, кто клал в ref то, что показывается на экране, а потом боролся с тем, что интерфейс не обновляется.
Как отвечать
Да, это одно из двух назначений useRef. Хук возвращает один и тот же объект на всё время жизни компонента, и запись в .current перерисовку не вызывает.
Туда кладут то, что нужно коду, но не нужно разметке: идентификатор таймера, предыдущее значение пропа, флаг «инициализация уже прошла», экземпляр внешней библиотеки, AbortController текущего запроса, актуальную версию колбэка, чтобы эффект не переподписывался на каждое изменение функции.
const timerRef = useRef(null);
useEffect(() => () => clearTimeout(timerRef.current), []);Критерий простой: значение влияет на то, что видит пользователь, значит это состояние, и место ему в useState или во внешнем сторе. Не влияет, подходит ref.
Отдельно про правило чтения и записи: .current трогают в обработчиках и эффектах, а не в теле компонента во время рендера. Рендер обязан быть чистым, а в строгом режиме разработки он выполняется дважды, и мутация по дороге даёт задвоенные значения. Привычное исключение только одно, ленивая инициализация с проверкой на пустоту.
Для React 19 стоит упомянуть, что ref приходит в функциональный компонент обычным пропом, и отдельная обёртка для проброса больше не нужна.
Где спотыкаются
Хранят в ref то, что рисуется, а потом добавляют фиктивное обновление состояния, лишь бы компонент перерисовался. Это верный признак того, что значение с самого начала было состоянием.
Читают .current прямо в теле компонента и удивляются старому значению. Во время рендера там лежит то, что записали раньше, а обновление после рендера экран уже не трогает, поэтому разметка и ref расходятся.
Путают useRef с мемоизацией. Запись вида useRef(создатьТяжёлыйОбъект()) честно вызывает функцию на каждом рендере, просто результат после первого раза выбрасывается. Тяжёлое создают лениво, по проверке на пустое значение.