React 18 introduced a low-level hook that most developers never touch directly, but almost every modern state library depends on:
useSyncExternalStore
It is React’s official way to connect components to external state sources — state that lives outside React.
Examples:
localStorage- Redux / Zustand stores
- browser APIs
- WebSocket data
What problem does it solve?
Before React 18, we usually subscribed to stores like this:
useEffect(() => store.subscribe(forceUpdate), []);
This breaks under concurrent rendering.
useSyncExternalStore fixes this by letting React control how it:
- subscribes to changes
- reads the current value
- triggers re-renders safely
The API
const value = useSyncExternalStore(
subscribe,
getSnapshot,
getServerSnapshot?
);
-
subscribe→ how React listens for updates -
getSnapshot→ how React reads current state
When the snapshot changes, React re-renders.
Example: persistent state with localStorage
1. Create a tiny external store
function createLocalStorageStore(key, initialValue) {
const listeners = new Set();
const getSnapshot = () => {
const data = localStorage.getItem(key);
return data ? JSON.parse(data) : initialValue;
};
const setValue = (value) => {
localStorage.setItem(key, JSON.stringify(value));
listeners.forEach((l) => l());
};
const subscribe = (listener) => {
listeners.add(listener);
const onStorage = (e) => {
if (e.key === key) listener();
};
window.addEventListener("storage", onStorage);
return () => {
listeners.delete(listener);
window.removeEventListener("storage", onStorage);
};
};
return { getSnapshot, setValue, subscribe };
}
2. Connect it to React
import { useSyncExternalStore } from "react";
function useExternalStore(store) {
return useSyncExternalStore(
store.subscribe,
store.getSnapshot,
store.getSnapshot
);
}
3. Use it
const counterStore = createLocalStorageStore("counter", 0);
function Counter() {
const count = useExternalStore(counterStore);
return (
<>
<p>Count: {count}</p>
<button onClick={() => counterStore.setValue(count + 1)}>
+
</button>
</>
);
}
Now your state is:
- persistent
- shared
- cross-tab synced
- concurrent-safe
When should you use this?
Use useSyncExternalStore when:
- state lives outside React
- many components share the same data
- you’re building a store, persistence layer, or library
For normal component state, useState is still the right tool.
Final takeaway
useState manages React-owned state.
useSyncExternalStore connects React to the outside world.
If you’re building anything beyond local component state, this hook is the foundation.
Top comments (0)