React’s useSyncExternalStore
hook is designed to connect React components to external sources of truth—like localStorage, WebSocket streams, or even Redux-style stores. While powerful, its internal magic can be hard to grasp. Let’s demystify it by building a simplified version from scratch.
Step 1: Set Up a Basic Store
This store will manage state outside of React and notify listeners when updates occur.
function createStore(initialValue) {
let value = initialValue;
const listeners = new Set();
return {
getSnapshot: () => value,
setValue: (newVal) => {
value = newVal;
listeners.forEach((l) => l());
},
subscribe: (listener) => {
listeners.add(listener);
return () => listeners.delete(listener);
},
};
}
Step 2: Build a Custom Hook
This custom hook mimics the signature of useSyncExternalStore
.
import { useEffect, useSyncExternalStore } from "react";
function useCustomStore(store) {
return useSyncExternalStore(
store.subscribe,
store.getSnapshot
);
}
Step 3: Use the Store in a Component
Let’s create a counter component that subscribes to the store and reacts to changes instantly.
const counterStore = createStore(0);
function Counter() {
const count = useCustomStore(counterStore);
return (
Count: {count}
);
}
✅ Pros
- Clean separation between state logic and UI.
- Supports external systems like WebSockets, browser APIs, etc.
- Fully concurrent-mode safe (when using
useSyncExternalStore
).
⚠️ Cons
- Still requires you to manage the store manually (no reducer helpers, etc.).
- Harder to debug compared to using React state directly.
- Won’t work in older versions of React (prior to 18).
Wrap-Up
If you’ve ever wanted to connect React to a global event system or shared non-React data, useSyncExternalStore
is the right tool—and now you know how to build it yourself. Try swapping in your own state containers, browser listeners, or even signals.
For a much more extensive guide on getting the most out of React portals, check out my full 24-page PDF file on Gumroad. It's available for just $10:
Using React Portals Like a Pro.
If this was helpful, you can support me here: Buy Me a Coffee ☕