External state libraries
A state-management library exposes data outside React and needs concurrent-safe React integration.
React 19+ · Hook
useSyncExternalStore lets a component read from and subscribe to an external store. It supports server rendering through an optional server snapshot and re-renders when the snapshot changes.
Call this Hook at the component’s top level with a subscription function and a snapshot reader. React invokes the reader after store notifications, compares snapshots, and re-renders when the value changes; an optional third function supplies the server and hydration snapshot.
const snapshot = useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot?)| Name | Type | Description |
|---|---|---|
subscribe | (callback: () => void) => () => void | Subscribes to the store with a callback and returns a cleanup function that unsubscribes. |
getSnapshot | () => Snapshot | Returns the immutable snapshot needed by the component; unchanged store state must produce the same value. |
getServerSnapshot | () => Snapshot | Optional initial snapshot used during server rendering and hydration; it must match between server and client. |
The current snapshot of the external store.
import { useSyncExternalStore } from 'react';
const onlineStore = {
subscribe(callback: () => void) {
window.addEventListener('online', callback);
window.addEventListener('offline', callback);
return () => {
window.removeEventListener('online', callback);
window.removeEventListener('offline', callback);
};
},
getSnapshot: () => navigator.onLine,
};
export function OnlineStatus() {
const online = useSyncExternalStore(
onlineStore.subscribe,
onlineStore.getSnapshot,
() => true,
);
return <p>{online ? 'Online' : 'Offline'}</p>;
}Reads browser connectivity through a stable subscription and supplies a server fallback for hydration.
A state-management library exposes data outside React and needs concurrent-safe React integration.
A browser API such as online/offline status changes independently of React state.
A server-rendered component reads external data that must match during hydration.
The Hook connects React to a store outside React. subscribe registers a callback and returns cleanup, while getSnapshot reads the data; React calls getSnapshot after notifications and re-renders when its result changes by Object.is.
Follow-up: Why must snapshots be cached? Repeated reads must return the same value when the store is unchanged, so a new object on every read can trigger endless updates.
subscribe receives React’s callback and must invoke it whenever the store changes. It must also return a cleanup function that removes the subscription.
Follow-up: What if subscribe changes identity between renders? React resubscribes using the new function, so define stable subscription logic when possible.
getServerSnapshot supplies the initial store value during server rendering and client hydration. The server and client values must match, commonly by serializing the server value for the client.
Follow-up: What happens without it in SSR? Rendering the component on the server throws an error.
useEffectuseStateuseSyncExternalStoreWithSelectorsubscribegetSnapshotgetServerSnapshot