Introduction
useSyncExternalStore is a React Hook introduced in React 18 to safely subscribe to external stores in concurrent rendering environments. It ensures that your component reads consistent data and avoids tearing issues when React renders components multiple times.
This hook is mainly used when integrating React with:
It provides a reliable way to subscribe to external data while supporting concurrent features.
Why useSyncExternalStore Is Needed
Before React 18, developers commonly used useEffect and useState to subscribe to external stores. However, this approach could cause inconsistencies during concurrent rendering.
useSyncExternalStore solves this by:
Ensuring the snapshot is always consistent
Supporting server-side rendering (SSR)
Preventing visual tearing
Working correctly with concurrent rendering
Syntax
const state = useSyncExternalStore(
subscribe,
getSnapshot,
getServerSnapshot?
);
Parameters
subscribe
A function that registers a callback and returns an unsubscribe function.
getSnapshot
Returns the current value from the store.
getServerSnapshot (optional)
Used for server-side rendering.
Example: Creating a Simple Custom Store
Let’s build a small counter store outside React.
Step 1: Create the Store
// counterStore.js
let count = 0;
const listeners = new Set();
export const counterStore = {
getSnapshot: () => count,
subscribe: (listener) => {
listeners.add(listener);
return () => listeners.delete(listener);
},
increment: () => {
count++;
listeners.forEach(listener => listener());
}
};
Step 2: Use useSyncExternalStore in a Component
import React, { useSyncExternalStore } from "react";
import { counterStore } from "./counterStore";
function Counter() {
const count = useSyncExternalStore(
counterStore.subscribe,
counterStore.getSnapshot
);
return (
<div>
<h2>Count: {count}</h2>
<button onClick={counterStore.increment}>
Increment
</button>
</div>
);
}
export default Counter;
Example: Using with Redux
If you're using Redux, modern versions internally use useSyncExternalStore. However, if implementing manually:
const state = useSyncExternalStore(
store.subscribe,
store.getState
);
This ensures safe subscription in concurrent mode.
Server-Side Rendering Example
const value = useSyncExternalStore(
store.subscribe,
store.getSnapshot,
() => initialServerValue
);
The third parameter ensures the correct snapshot is used during SSR.
When to Use useSyncExternalStore
Use it when:
You are building a custom state management solution
You are integrating a non-React store
You need concurrent-safe subscriptions
You are working on library-level code
Avoid it for normal component state. For most use cases, useState and useReducer are sufficient.
Common Mistakes
Returning a new object in getSnapshot every time
This causes unnecessary re-renders.
Not properly cleaning up in subscribe
Always return an unsubscribe function.
Using it for local state
It is meant for external stores only.
Conclusion
useSyncExternalStore is a low-level React Hook designed for safely subscribing to external data sources in React 18 and beyond. It ensures consistency during concurrent rendering and supports server-side rendering seamlessly.
While most applications do not need to use it directly, it becomes essential when building custom state management systems or integrating external libraries. Understanding how it works gives deeper insight into how React handles synchronization and rendering under the hood.