В чем разница между хранением массива в useState и useRef в React
Что проверяют
Понимаете ли вы, что рендер вызывает только изменение состояния, и знаете ли, что React сравнивает ссылки, а не содержимое.
Как отвечать
Массив в useState это данные для экрана: заменили его новым, компонент перерисовался, список обновился. Массив в useRef живёт в ref.current, переживает рендеры, но его изменение экран не трогает.
Отсюда правило: массив виден пользователю, берём useState; массив нужен только логике (накопленные события, набор таймеров, буфер измерений, предыдущее значение), берём useRef.
Критичная деталь: с useState массив нельзя менять на месте.
items.push(next); // ссылка та же, React ничего не заметит
setItems(items);
setItems((prev) => [...prev, next]); // новый массив, рендер будетЧто ещё стоит назвать:
- обновление через функцию (
prev => ...) обязательно, когда новое значение зависит от старого: несколько вызовов подряд иначе перетрут друг друга; - в
useRefмутация на месте допустима и даже удобна: это обычный объект, никакой сверки нет; - значение из
useRefнельзя читать во время рендера, только в обработчиках и эффектах, иначе результат зависит от порядка вычислений; - для большого массива со сложными правилами обновления удобнее
useReducer, чем набор вызовов сеттера.
Где спотыкаются
Мутируют массив состояния и ждут перерисовки.
Кладут в useRef то, что должно отображаться, и потом добавляют искусственный forceUpdate.
Забывают, что новый массив на каждый рендер (items.filter(...) прямо в теле) ломает мемоизацию дочерних компонентов, потому что ссылка каждый раз новая.