← Все статьи

React useLatest: свежее состояние в async-колбэках без лишних рендеров

Хук useLatest из @reactuses/core: актуальный ref в layout-эффекте против устаревших замыканий после await, в таймерах и подписках.

React useLatest: свежее состояние в async-колбэках без лишних рендеров
Содержание

Коротко

Кнопка «Сохранить» ставит статус saved, пока пользователь ещё печатает: замыкание держит старый text. Статья на Dev.to разбирает useLatest из @reactuses/core — стабильный ref, который в layout-эффекте всегда указывает на последнее закоммиченное значение и читается из колбэков после await, таймеров и подписок.

Что произошло

Любой колбэк, переживший свой рендер (await, setTimeout, слушатель, SDK), видит props и state того рендера, где его создали. Это нормальное замыкание; баг — когда нужно «сейчас», а получили «тогда».

useLatest(value) возвращает стабильный ref: .current обновляется в isomorphic layout-эффекте, не во время рендера (concurrent-рендеринг может отбросить рендер). В примере автосохранения замыкание хранит снимок для отправки, ref — текст после ответа API, чтобы выбрать saved или dirty.

Рядом: useEvent / useEffectEvent — для функций; useLatest — для значений. Типовые места: гонка поиска в обработчике, карта или WebSocket с пустым массивом зависимостей, тост с паузой при наведении.

Почему это важно

«Положить state в зависимости эффекта» часто означает рвать дорогую подписку. Ref даёт честный пустой массив зависимостей и свежие данные внутри. Ошибка — читать .current в JSX: для экрана нужен useState.

На практике

  1. После await сравнивайте отправленный снимок с latest.current.
  2. Подписки «один раз» читайте через ref, а не через зависимости, которые пересоздают клиент.
  3. Пишите в ref в layout-эффекте, не в теле рендера.
  4. Функцию в ребёнка или эффект — через useEvent; значение в колбэк — через useLatest.
  5. Не кладите ref в зависимости «чтобы среагировать» — его identity стабилен.

Итог

useLatest — маленький паттерн против устаревших замыканий: всегда актуален из колбэка, не триггерит ререндер и не меняет identity. Для UI по-прежнему state.