What is useSyncExternalStore in React?
useSyncExternalStore is a built-in React hook introduced
in React 18 that allows your components to subscribe to external data
sources. This article explains why this hook is necessary for concurrent
rendering, how its API works, and provides a practical example of how to
implement it to keep your application state in sync with external stores
or browser APIs.
In React 18, the introduction of concurrent rendering allowed React
to pause and resume rendering to keep the main thread responsive.
However, this introduced a problem called “tearing” when components read
from external, mutable data stores (such as Redux, MobX, or global
window variables) that change during rendering. Tearing occurs when
different parts of the UI display inconsistent data for the same state.
useSyncExternalStore solves this by forcing synchronous
updates when the external store changes, ensuring UI consistency.
The API Syntax
The hook accepts three arguments and returns the current state 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 whenever the store changes, triggering a re-render. It should return a cleanup function to unsubscribe.getSnapshot: A function that returns the current value of the store. If the value hasn’t changed, it must return the exact same reference (cached value) to prevent unnecessary re-renders.getServerSnapshot: An optional function that returns the initial value of the store during server-side rendering (SSR) or hydration.
Practical Example: Subscribing to Browser Online Status
One of the most common use cases for
useSyncExternalStore is subscribing to native browser APIs,
such as the network online status (navigator.onLine).
import { useSyncExternalStore } from 'react';
function subscribe(callback) {
window.addEventListener('online', callback);
window.addEventListener('offline', callback);
return () => {
window.removeEventListener('online', callback);
window.removeEventListener('offline', callback);
};
}
function getSnapshot() {
return navigator.onLine;
}
export function ChatStatus() {
const isOnline = useSyncExternalStore(subscribe, getSnapshot);
return (
<div>
<p>Your connection status: <strong>{isOnline ? 'Online' : 'Offline'}</strong></p>
</div>
);
}In this example, the subscribe function listens for the
browser’s online and offline events and
triggers a re-render. The getSnapshot function returns the
current boolean state of navigator.onLine.
When Should You Use It?
You should use useSyncExternalStore when: * You are
building or maintaining third-party state management libraries (like
Zustand or Redux) that manage state outside of React’s built-in state. *
You need to subscribe to native browser APIs, such as window dimensions,
geolocation, or connection status, that change over time.
You should not use it for: * Managing standard component state (use
useState or useReducer instead). * Handling
side effects that can be managed within the standard React lifecycle
(use useEffect instead).