useSyncExternalStore: подписка React на внешний источник

useSyncExternalStore: подписка React на внешний источник
Содержание статьи

Когда состояние живёт за пределами React, компоненту нужны чтение текущего значения и подписка на изменения. Для этой связи предназначен useSyncExternalStore. На Mentoring.digital разберём контракт на браузерном флаге подключения, не превращая его в обещание доступности сервера.

Разделите чтение снимка и подписку

getSnapshot возвращает текущее значение, а subscribe принимает функцию уведомления React и возвращает очистку подписки. Функции вынесены за компонент, поэтому их ссылки не меняются при каждом рендере.

import { useSyncExternalStore } from "react";

function subscribe(onStoreChange) {
  window.addEventListener("online", onStoreChange);
  window.addEventListener("offline", onStoreChange);
  return () => {
    window.removeEventListener("online", onStoreChange);
    window.removeEventListener("offline", onStoreChange);
  };
}

function getSnapshot() {
  return navigator.onLine;
}

function getServerSnapshot() {
  return true;
}

export default function ConnectionHint() {
  const online = useSyncExternalStore(
    subscribe, getSnapshot, getServerSnapshot
  );
  return <p>{online
    ? "Браузер сообщает о подключении"
    : "Браузер сообщает об отсутствии подключения"}</p>;
}

Пример предназначен для проекта React с обработкой JSX. Булево значение является удобным снимком: пока состояние не изменилось, его результат остаётся тем же при сравнении через Object.is.

Почему нельзя каждый раз возвращать новый объект

Если getSnapshot на каждом вызове создаёт новый объект с теми же данными, React видит новое значение. Для изменяемого внешнего хранилища возвращайте закешированный неизменяемый снимок и создавайте следующий только после фактического изменения данных.

subscribe должен уведомлять React о возможном изменении. React затем перечитывает снимок. Очистка обязана снимать именно те слушатели, которые были добавлены: это важно при размонтировании и повторном подключении компонента.

Что учесть при серверном рендеринге

Третий аргумент используется на сервере и при начальной гидратации в браузере. Его значение должно совпадать в этих двух точках. Здесь это намеренно выбранное исходное true, а не измеренное состояние сети пользователя. После подключения React читает настоящий браузерный снимок.

Для пользовательских данных передавайте согласованное начальное состояние вместе с серверной страницей. Не обращайтесь к window или navigator на сервере. Отсутствие getServerSnapshot при серверном рендеринге компонента приводит к ошибке.

Как проверить смысл индикатора

В тестовом проекте переключите режим Offline в инструментах браузера и верните подключение. Затем скройте компонент и проверьте снятие слушателей. Если ваш источник возвращает объект, отдельно проверьте стабильность снимка без изменений.

navigator.onLine опирается на эвристики браузера. Значение true не доказывает доступность API приложения. Ошибку реального запроса обрабатывайте отдельно и не запрещайте действие только по этому флагу.

Подписки и рендеринг можно отработать на курсе React, а устройство внешнего хранилища обсудить с наставником по React.

Похожие статьи по данной теме