7 апреля 2023 г. (изменено: 7 апреля 2023 г.)

Канал: @cherkashindev

630

📖 React 18 — useTransition, useDeferredValue

React 18 вышел уже почти год назад, но только сейчас решил поискать наглядные примеры использования новых хуков useTransition и useDeferredValue и наткнулся на отличное видео “Новые хуки useTransition и useDeferredValue в React 18”. Оба хука работают благодаря конкурентному режиму, который позволяет прерывать рендеринг.

Пример

Допустим у нас есть поле поиска и очень длинный список заказов. При каждом изменении мы ре-рендерим список. Например, вы хотите купить новый айфон и вводите iphone в поле поиска, ре-рендеринг произойдёт 6 раз (для значений i, ip, iph ipho, iphon, iphone) — на каждое изменение. К тому же пока рендеринг не завершён — основной поток приложения заблокирован и пользователь не может взаимодействовать с приложением, из-за чего страдает UX. Однако это очень не оптимально, ведь когда мы вводим каждый новый символ, предыдущие результаты поиска для нас больше неактуальны и было бы логичнее приостановить рендеринг и запустить новый.

Именно эту проблему решают новые хуки, они позволяют приостановить или отменить запущенный рендеринг, если есть более важное событие, например, ввод пользователя.

Вероятно вы не замечаете проблем с производительностью на своём Macbook Pro M2, но далеко не у всех пользователей такие же шустрые устройства. Но вы можете стать ближе к народу и включить эмуляцию медленной производительности в DevTools в Performance ⇒ CPU ⇒ 6x slowdown.

useDeferredValue не содержит конкретного таймаута, для обновления значения. Реакт сам решит, когда значение будет обновлено в зависимости от от того, насколько Реакт в данный момент занят другими вычислениями. Принцип работы хука довольно простой, когда useDeferredValue получает новое значение — под капотом запускается ре-рендер, если этот ре-рендер не прерван — UI обновляется. Но если хук получил ещё одно новое значение — то старое состояние устарело, вычисление виртуального дома прерывается и процесс начинается заново.

Принцип работы работы useTransition аналогичен — если startTransition запускается несколько раз — отрендерится лишь последний результат, а все предыдущие будут прерваны.

Оба хука взаимозаменяемы:

  • Используйте useTransition, если у вас есть доступ к обновлению состояния
  • Используйте useDeferredValue, например, если вам необходимо запустить обновление в ответ на изменение пропса.

Подход похож на debounce, но это не одно и то же. Когда мы используем debounce, рендер просто откладывается, но мы не можем его прервать, и UI всё равно может зависнуть через указанный таймаут.

Ещё по теме