Вопрос проверяет понимание границы ответственности React и умение корректно интегрировать внешнее состояние с его механизмом рендера.
React сам по себе не знает о внешнем состоянии, поэтому его нужно явно “подключить” к процессу рендера. Обычно это делается через подписку на изменения внешнего стора и принудительный ререндер компонента. Современный и рекомендуемый способ — использовать useSyncExternalStore. Именно так работают Redux, Zustand и другие state-менеджеры.
Связка внешнего состояния и React-рендеринга строится вокруг одной идеи: внешний стор должен уметь уведомлять React об изменениях.
External store — это источник состояния, который живёт вне React (обычный JS-объект, singleton, класс, Redux-store, кастомный стор).
Ключевая проблема:
React не подписывается на такие объекты автоматически.
Перед деталями важно зафиксировать общий алгоритм:
Внешний стор хранит данные.
Внешний стор умеет уведомлять подписчиков об изменениях.
React-компонент подписывается на стор.
При уведомлении React инициирует ререндер.
Самый простой, но “низкоуровневый” подход.
function useExternalStore(store) {
const [, forceRender] = useState(0);
useEffect(() => {
return store.subscribe(() => {
forceRender((v) => v + 1);
});
}, [store]);
return store.getState();
}
forceRender используется только для запуска ререндера.
Реальное состояние берётся из стора.
Минусы:
легко ошибиться
плохо совместим с concurrent rendering
Официальный API React для внешних сторов.
const state = useSyncExternalStore(
store.subscribe,
store.getState
);
Плюсы:
Корректно работает в StrictMode.
Безопасен для concurrent rendering.
Гарантирует консистентность данных.
Redux, Zustand, MobX уже реализуют эту логику:
Подписка инкапсулирована внутри библиотеки.
Компоненты получают готовые хуки (useSelector, useStore).
Минимизируются лишние ререндеры.
Чтобы связать external store с React, нужно не менять данные напрямую, а встроить механизм подписки, который будет корректно инициировать ререндер — лучше всего через useSyncExternalStore.