What does `useSyncExternalStore()` do?
What useSyncExternalStore() does
useSyncExternalStore() connects a React component to external state
that React does not manage (for example, Redux, Zustand, an EventEmitter, a custom store, window.location, and so on).
It provides:
- synchronous reading of the current value (a store snapshot),
- subscription to updates,
- correct behavior with concurrent rendering (React 18) and SSR.
More simply:
useSyncExternalStore()lets React components reliably read data from an external store and update when it changes.
Syntax
const state = useSyncExternalStore(
subscribe, // subscription function
getSnapshot, // function that reads the current state
getServerSnapshot? // (optional) version for SSR
);Example: connecting to a custom store
Say we have a simple store outside of React:
// store.js
let listeners = [];
let count = 0;
export function increment() {
count++;
listeners.forEach((l) => l());
}
export function subscribe(listener) {
listeners.push(listener);
return () => {
listeners = listeners.filter((l) => l !== listener);
};
}
export function getSnapshot() {
return count;
}Now let's connect it to React through useSyncExternalStore:
import { useSyncExternalStore } from "react";
import { subscribe, getSnapshot, increment } from "./store";
function Counter() {
const count = useSyncExternalStore(subscribe, getSnapshot);
return (
<div>
<p>Count: {count}</p>
<button onClick={increment}>+1</button>
</div>
);
}Now:
- The component gets the up-to-date value from
getSnapshot()immediately; - When the store changes,
subscribe()fires -> React re-renders the component; - Everything works synchronously and predictably, even in concurrent mode.
What each argument does
| Argument | What it does |
|---|---|
subscribe(listener) | Registers a callback that is called when the state changes; returns an unsubscribe function |
getSnapshot() | Returns the current value of the state from the external source |
getServerSnapshot() (optional) | A version of getSnapshot for SSR, so the server and client stay in sync |
Why this appeared in React 18
Previously, custom hooks like useStore, useSelector, and so on were used for this.
But with the arrival of Concurrent Rendering, React started rendering several versions of the UI "at once".
The problem with the old solutions:
- They could pick up a "stale" value from the store,
- Or cause "desynchronization" (the UI showed something different from what was actually in the store).
useSyncExternalStore solves this, because it:
- Guarantees that React always reads the current snapshot of the state,
- And updates synchronously if the store changes during rendering.
Example: integration with Redux
Redux 8+ now uses useSyncExternalStore internally.
import { useSelector } from "react-redux";
function MyComponent() {
const count = useSelector((state) => state.counter.value);
return <div>{count}</div>;
}Inside, useSelector is implemented roughly like this:
function useSelector(selector) {
return useSyncExternalStore(
store.subscribe,
() => selector(store.getState())
);
}Example with window.location (an external source)
function useLocation() {
return useSyncExternalStore(
(callback) => {
window.addEventListener("popstate", callback);
return () => window.removeEventListener("popstate", callback);
},
() => window.location.pathname
);
}
function RouterView() {
const path = useLocation();
return <div>Current path: {path}</div>;
}React will automatically update the component when window.location changes.
The SSR version (getServerSnapshot)
With server-side rendering (Next.js, Remix, and so on) you can pass a 3rd argument:
useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);This matters so that the value on the server and the client match, otherwise React will emit a "mismatched hydration" warning.
When to use it
| When | Why |
|---|---|
| You are connecting to an external store (Redux, Zustand, a custom store) | React does not manage this state |
| You need a reactive subscription | The component must re-render when the store changes |
| It matters to avoid desynchronization in Concurrent Rendering | useSyncExternalStore guarantees consistency |
| You need safe behavior under SSR | You can pass getServerSnapshot |
When you don't need it
| Case | Why |
|---|---|
You work with state through useState or useReducer | React manages the data itself - useSyncExternalStore is unnecessary |
| You are making API requests | Use useEffect / React Query |
| The store is local, not global | Overkill |
Summary
| Question | Answer |
|---|---|
What does useSyncExternalStore() do | Lets a React component subscribe to external state (a store) and get up-to-date data |
| Arguments | (subscribe, getSnapshot, getServerSnapshot?) |
| Why it is needed | For state consistency under Concurrent Rendering and SSR |
| Where it is used | Redux, Zustand, Jotai, custom stores, event emitters |
| Do not use it for | Local React state (useState, useReducer) |
Main idea:
useSyncExternalStore()is the "official way" to synchronously connect React to external state without the risk of desynchronization between the store and the UI.
Short Answer
Interview readyA concise answer to help you respond confidently on this topic during an interview.