How to Use useSyncExternalStore in React
This guide explains how to implement the
useSyncExternalStore hook in React to subscribe to external
data stores. You will learn what this hook does, understand its syntax,
and walk through a practical code example to integrate third-party state
managers or browser APIs with React’s concurrent rendering features.
Why useSyncExternalStore?
Introduced in React 18, useSyncExternalStore is a
built-in hook designed to subscribe to data sources external to React
(such as Redux, Zustand, browser APIs, or global variables). Using
traditional hooks like useEffect and useState
for external stores can cause “tearing”—a visual inconsistency where
different components render different values for the same state during a
single transition. useSyncExternalStore guarantees
synchronous updates, preventing this issue.
The Syntax
The hook accepts three arguments and returns the current snapshot of the store:
const state = useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot?);subscribe: A function that registers a callback with the external store. React will call this function to listen for changes. It must return a cleanup function to unsubscribe.getSnapshot: A function that returns the current value of the store. If the store hasn’t changed, it must return the exact same value (using strict equality===).getServerSnapshot(Optional): A function that returns the initial snapshot during Server-Side Rendering (SSR) or hydration.
Step-by-Step Implementation
Below is a step-by-step example of using
useSyncExternalStore to track the user’s internet
connection status using the browser’s navigator.onLine
API.
Step 1: Define the Subscribe Function
The subscribe function registers event listeners for the
browser’s online and offline events. When
these events fire, React is notified via the callback
trigger.
function subscribe(callback) {
window.addEventListener('online', callback);
window.addEventListener('offline', callback);
// Return the cleanup function to remove listeners
return () => {
window.removeEventListener('online', callback);
window.removeEventListener('offline', callback);
};
}Step 2: Define the Snapshot Function
The getSnapshot function reads the current status
directly from the browser API. It must return a primitive value or a
memoized object to prevent unnecessary re-renders.
function getSnapshot() {
return navigator.onLine;
}Step 3: Implement the Hook in a Component
Pass both functions to useSyncExternalStore inside your
React component to retrieve the synchronized state.
import { useSyncExternalStore } from 'react';
export function ConnectionIndicator() {
const isOnline = useSyncExternalStore(subscribe, getSnapshot);
return (
<div className="status-container">
<p>
Connection Status:
<span style={{ color: isOnline ? 'green' : 'red' }}>
{isOnline ? ' ● Online' : ' ● Offline'}
</span>
</p>
</div>
);
}Important Considerations
- Immutable Snapshots: If your external store
contains objects,
getSnapshotmust return an immutable copy of the object only when the data changes. If it returns a newly created object reference on every call, React will trigger an infinite loop of re-renders. - Static Reference: Ensure the
subscribeandgetSnapshotfunctions are declared outside of your component (like in the example above) or memoized withuseCallbackso their references remain stable between renders.