Используй ref вместо useState, где возможно!
Все мы любим useState: просто, наглядно, перерисовывает компонент при каждом обновлении. Но иногда это «перерисовывает» — самая большая проблема. 👀
Давайте разберём, когда лучше достать из инструментов useRef, чтобы не трогать рендер‑цикл лишний раз.
Перезаписывая состояние, мы запускаем полный цикл рендера. Для локальных счётчиков или контролируемых полей это нормально. Но когда речь про таймеры, промежуточные значения, значения DOM — мы понапрасну грузим компонент.
Условный «предыдущий ID запроса» никак не влияет на разметку. Зачем держать его в state, если можно хранить в ref?
const timerRef = useRef<number | null>(null);
useEffect(() => {
timerRef.current = window.setInterval(() => {
// ... логика интервала
}, 1000);
return () => {
if (timerRef.current !== null) {
window.clearInterval(timerRef.current);
}
};
}, []);Храним идентификатор таймера в ref — никаких лишних ререндеров, а при unmount можно корректно очистить интервал.
const previousQueryRef = useRef<string>('');
useEffect(() => {
previousQueryRef.current = query;
}, [query]);
const isRepeated = previousQueryRef.current === query;Нам нужно помнить прошлый запрос, но выводить его не нужно. Значит, ref подходит идеально.
const inputRef = useRef<HTMLInputElement>(null);
const focus = () => {
inputRef.current?.focus();
};useRef даёт ссылку на DOM‑элемент. Мы можем фокусировать инпут, не дёргая состояние и не обновляя компонент.
const chartInstanceRef = useRef<Chart | null>(null);
useEffect(() => {
chartInstanceRef.current = initChart(canvasElement);
return () => chartInstanceRef.current?.destroy();
}, []);Экземпляр графика нужно хранить между рендерами, но он не меняет UI. Значит, ref — наш выбор.
Если значение влияет на шаблон — оставляем его в state. Несмотря на перерендер, это честный и предсказуемый способ обновления UI.
| Задача | useState | useRef |
|---|---|---|
| Управляемый UI | ✅ | 🚫 |
| DOM‑элементы | 🚫 | ✅ |
| Таймеры, интервалы | 🚫 | ✅ |
| Внешние инстансы (карты, графики) | 🚫 | ✅ |
| Кэш значений между рендерами | 🚫 | ✅ |
useRef — это не про «где-то храню данные». Это про контроль за тем, что действительно влияет на интерфейс. Если значение нужно только логике, а не верстке — кладём его в ref. Так компонент остаётся быстрым, а код — предсказуемым. 🚀