When to Avoid useSyncExternalStore in React
While useSyncExternalStore is a powerful React hook
designed to subscribe to external data sources, it is not a
one-size-fits-all solution for state management. This article explains
when you should avoid using useSyncExternalStore, detailing
scenarios where native React state hooks, context, or standard
data-fetching libraries are more appropriate for your application’s
performance and maintainability.
1. For Internal React State
You should avoid useSyncExternalStore if the state you
are managing is local to a component or can be managed within the React
lifecycle. If you are not integrating with a third-party, non-React
state manager (such as Zustand, Redux, or native browser APIs like
window.matchMedia), you should stick to standard hooks like
useState or useReducer. Using
useSyncExternalStore for internal state adds unnecessary
complexity without any performance benefits.
2. When You Need Concurrent Rendering and Transitions
One of the key features of React 18 is concurrent rendering, which
allows React to interrupt a slow render to keep the UI responsive (using
useTransition or useDeferredValue).
useSyncExternalStore is specifically designed to guarantee
that the UI stays strictly in sync with the external store, which means
it deliberately disables time-slicing and forces synchronous updates to
prevent visual “tearing.” If your application relies on transitions to
keep the UI responsive during heavy state updates, this hook will bypass
those benefits.
3. For Asynchronous Data Fetching
The useSyncExternalStore hook expects synchronous access
to the current snapshot of the data. If your data source is
asynchronous—such as standard HTTP API fetches, GraphQL queries, or raw
Promises—this hook is not suitable on its own. Instead, use established
asynchronous state management solutions like TanStack Query (React
Query), SWR, or React’s built-in Suspense-based data-fetching
patterns.
4. For Simple Derived State
If you need to calculate a value based on existing props or state,
you should not spin up an external store. You should compute derived
state directly during render, or wrap the calculation in
useMemo if it is computationally expensive. Relying on an
external store subscription for derived state introduces unnecessary
overhead and complicates the data flow of your application.