Що таке useSyncExternalStore в React?
Що таке useSyncExternalStore?
useSyncExternalStore — це хук React 18+ для підписки на зовнішні сховища — джерела даних, які існують поза React (API браузера, сторонні бібліотеки стану, глобальні змінні). Він забезпечує послідовне читання під час паралельного рендерингу.
Чому це потрібно
При паралельному рендерингу React може "призупинити" та "відновити" рендеринг. Без useSyncExternalStore ви можете прочитати різні значення зовнішнього сховища під час одного рендерингу — помилка, відома як розрив.
Основний API
const value = useSyncExternalStore(
subscribe, // Функція для підписки на зміни
getSnapshot, // Функція для отримання поточного значення
getServerSnapshot // Необов'язково: значення для SSR
);Приклад: Статус онлайн
function useOnlineStatus() {
return useSyncExternalStore(
// subscribe — викликається, коли змінюється сховище
(callback) => {
window.addEventListener("online", callback);
window.addEventListener("offline", callback);
return () => {
window.removeEventListener("online", callback);
window.removeEventListener("offline", callback);
};
},
// getSnapshot — повертає поточне значення
() => navigator.onLine,
// getServerSnapshot — значення для SSR
() => true
);
}
function StatusBar() {
const isOnline = useOnlineStatus();
return <div>{isOnline ? "🟢 Онлайн" : "🔴 Офлайн"}</div>;
}Приклад: Ширина вікна
function useWindowWidth() {
return useSyncExternalStore(
(callback) => {
window.addEventListener("resize", callback);
return () => window.removeEventListener("resize", callback);
},
() => window.innerWidth,
() => 1024 // Значення за замовчуванням для сервера
);
}
function Layout() {
const width = useWindowWidth();
return width > 768 ? <DesktopLayout /> : <MobileLayout />;
}Приклад: localStorage
function useLocalStorage<T>(key: string, initialValue: T) {
const subscribe = (callback: () => void) => {
window.addEventListener("storage", callback);
return () => window.removeEventListener("storage", callback);
};
const getSnapshot = () => {
const item = localStorage.getItem(key);
return item ? JSON.parse(item) : initialValue;
};
const getServerSnapshot = () => initialValue;
return useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);
}
// Використання
function Settings() {
const theme = useLocalStorage("theme", "light");
return <div>Поточна тема: {theme}</div>;
}Як бібліотеки стану це використовують
Бібліотеки, такі як Zustand і Redux, внутрішньо використовують useSyncExternalStore:
// Спрощена концепція реалізації Zustand
function useStore<T>(store: Store<T>, selector: (state: T) => any) {
return useSyncExternalStore(
store.subscribe,
() => selector(store.getState()),
() => selector(store.getInitialState())
);
}Коли використовувати
| Сценарій | Використовувати |
|---|---|
| Стан React (useState, useReducer) | ❌ Не потрібно |
| API браузера (онлайн, зміна розміру, медіа-запит) | ✅ useSyncExternalStore |
| Сторонні сховища (без прив'язок до React) | ✅ useSyncExternalStore |
| Створення бібліотеки управління станом | ✅ useSyncExternalStore |
| Читання з localStorage/sessionStorage | ✅ useSyncExternalStore |
Важливо:
useSyncExternalStore запобігає розриву в паралельному React, забезпечуючи послідовне читання з зовнішніх джерел даних. Використовуйте його для API браузера, сторонніх сховищ і будь-якого нестандартного стану. Якщо ви використовуєте стан React (useState/useReducer), вам це не потрібно — React вже коректно обробляє їх.
Коротка відповідь
Для співбесідиКоротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.