DevAcademy
LearnReactuseSyncExternalStore
IntermediateReact

useSyncExternalStore

Learn how to safely subscribe a component to a data store that lives outside of React.

Reading Time

16 min

Lesson

Lesson 25 of 42

The Problem: External State Sources

Some data doesn’t live in React state at all — browser APIs like window.innerWidth, navigator.onLine, or a third-party state library’s store. Subscribing to these with a plain useEffect + useState pattern can produce subtly inconsistent UI under React’s concurrent rendering features.

What useSyncExternalStore Does

useSyncExternalStore(subscribe, getSnapshot) reads a value from an external store and automatically re-renders the component whenever that store changes, in a way that stays consistent even with concurrent rendering — this is the same mechanism state management libraries like Redux and Zustand use internally.

Subscribing to the Browser’s Online Status

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;
}

function useOnlineStatus() {
  return useSyncExternalStore(subscribe, getSnapshot);
}

function StatusBadge() {
  const isOnline = useOnlineStatus();
  return <span>{isOnline ? "🟢 Online" : "🔴 Offline"}</span>;
}

useSyncExternalStore Arguments

ArgumentPurpose
subscribeA function that subscribes a callback to store changes, returning an unsubscribe function
getSnapshotA function that returns the store’s current value
getServerSnapshot (optional)A snapshot to use during server rendering, if the store doesn’t exist on the server

Why Not Just useEffect + useState?

A manual useEffect subscription can read a stale snapshot during React’s concurrent rendering, since the effect runs slightly after render. useSyncExternalStore is specifically designed to always return a value that’s torn-free and consistent with the rest of the render, even if the store changes mid-render.

Server Snapshot for SSR

function useOnlineStatus() {
  return useSyncExternalStore(
    subscribe,
    () => navigator.onLine,
    () => true // getServerSnapshot: assume "online" during server rendering
  );
}

Mostly a Library-Author Tool

Most application code never calls useSyncExternalStore directly — it’s primarily used inside state management libraries (Redux, Zustand, Jotai) to implement their own React bindings correctly. Recognizing it helps when reading those libraries’ source code.

Best Practice

Reach for useSyncExternalStore only when subscribing directly to a genuinely external store outside of React’s own state (a browser API, a custom event emitter, or a non-React library) — for anything backed by React state itself, useState/useReducer/Context are the right tools.

Interview Questions

Quick Quiz

1. What kind of data source is useSyncExternalStore designed for?

2. What does the getSnapshot function need to return?

3. Why is useSyncExternalStore preferred over a manual useEffect + useState subscription for external stores?