🪝 Introduction to useSyncExternalStore
The useSyncExternalStore Hook is a React Hook that lets components subscribe to an external data store. It keeps React components synchronized with data that exists outside React, such as browser APIs, global state libraries, or custom stores, while ensuring consistent rendering.
Important
🎯 Why Use useSyncExternalStore?
React state managed with Hooks such as useState lives inside React. However, some applications rely on data managed outside React, including browser APIs, custom event emitters, or state management libraries. useSyncExternalStore provides a standard way to subscribe to these external sources and ensures React always renders using a consistent snapshot of the store.
- Subscribe to external stores.
- Keep React synchronized with outside data.
- Support concurrent rendering safely.
- Reduce manual subscription logic.
⚙️ Syntax
Basic Syntax
const snapshot = useSyncExternalStore(
subscribe,
getSnapshot,
getServerSnapshot
);| Parameter | Description |
|---|---|
| subscribe | Registers a listener and returns an unsubscribe function. |
| getSnapshot | Returns the current value from the external store. |
| getServerSnapshot | Provides the snapshot during server-side rendering. This parameter is optional for client-only applications. |
🔄 How useSyncExternalStore Works
💻 Example 1: Custom External Store
Basic Store Subscription
import { useSyncExternalStore } from "react";
const store = {
value: 0,
listeners: new Set(),
subscribe(listener) {
this.listeners.add(listener);
return () => {
this.listeners.delete(listener);
};
},
getSnapshot() {
return this.value;
}
};
function Counter() {
const count = useSyncExternalStore(
store.subscribe.bind(store),
store.getSnapshot.bind(store)
);
return <h2>{count}</h2>;
}The component automatically re-renders whenever the external store notifies its subscribers.
💻 Example 2: Browser Online Status
Tracking Network Status
import { useSyncExternalStore } from "react";
function subscribe(callback) {
window.addEventListener("online", callback);
window.addEventListener("offline", callback);
return () => {
window.removeEventListener("online", callback);
window.removeEventListener("offline", callback);
};
}
function getSnapshot() {
return navigator.onLine;
}
function NetworkStatus() {
const isOnline = useSyncExternalStore(
subscribe,
getSnapshot
);
return (
<p>
{isOnline ? "Online" : "Offline"}
</p>
);
}Whenever the browser's network status changes, the component automatically updates to display the latest state.
📊 Manual Subscription vs useSyncExternalStore
| Manual Subscription | useSyncExternalStore |
|---|---|
| Requires useEffect and cleanup. | Handles subscriptions using a standard API. |
| More boilerplate code. | Cleaner subscription logic. |
| Easy to introduce synchronization bugs. | Designed for consistent rendering. |
| Manual snapshot management. | React reads snapshots automatically. |
📅 Subscription Lifecycle
The component renders.
React reads the current snapshot from the external store.
The component subscribes to store updates.
The external store changes and notifies subscribers.
React reads the updated snapshot and re-renders the component.
🎯 Common Use Cases
Connect React components to external state management libraries.
Monitor browser APIs such as network connectivity or media queries.
Subscribe to custom event emitters or application-wide stores.
Display live data that changes independently of React state.
⚠️ Common Mistakes
- Using useSyncExternalStore for ordinary React state.
- Returning inconsistent values from getSnapshot.
- Forgetting to return an unsubscribe function from subscribe.
- Using this Hook when useState or useContext would be simpler.
Warning
📊 useSyncExternalStore vs useEffect
| Feature | useSyncExternalStore | useEffect |
|---|---|---|
| Purpose | Subscribe to external stores. | Run side effects. |
| Data Source | External state. | Any side-effect logic. |
| Automatic Snapshot Reading | Yes. | No. |
| Typical Usage | Global stores, browser APIs, subscriptions. | Fetching data, timers, subscriptions, DOM interactions. |
✅ Best Practices
- Use useSyncExternalStore only for data managed outside React.
- Ensure subscribe returns a proper cleanup function.
- Keep getSnapshot fast and predictable.
- Provide getServerSnapshot when supporting server-side rendering.
- Continue using React state Hooks for component-local state.
📚 Official Resource
Learn more about useSyncExternalStore in the official React documentation at React useSyncExternalStore Documentation.