Hirefullstack – Software Engineering & IT-Beratung aus Berlin
← Back to overview
Advanced 9 min read

useSyncExternalStore

Connecting React to something that lives outside it

Builds on: useEffect
In one sentence

The official way to connect React to something outside it – “is the browser online?”, for example.

Good to know You will rarely need this one yourself

It is mainly meant for libraries. Still worth a look: it explains how Zustand, Redux and friends plug into React these days – and for browser values it is the cleanest solution there is.

Some values do not belong to React: whether the browser is online, how wide the window is, what sits in a store of your own. React only learns about their changes if somebody tells it. That is exactly what this hook arranges.

shape.ts
const value = useSyncExternalStore(
  subscribe,        // (wakeUp) => cleanup   – reports changes to React
  getSnapshot,      // () => current value   – in the browser
  getServerSnapshot // () => value during SSR – optional, but important in Next.js
);
online.tsx
function subscribe(wakeUp: () => void) {
  window.addEventListener("online", wakeUp);
  window.addEventListener("offline", wakeUp);
  return () => {
    window.removeEventListener("online", wakeUp);
    window.removeEventListener("offline", wakeUp);
  };
}

export function useOnline() {
  return useSyncExternalStore(
    subscribe,
    () => navigator.onLine,   // browser
    () => true                // server: assume "online"
  );
}
Why not just useState + useEffect?
can briefly be out of date
const [online, setOnline] = useState(navigator.onLine);

useEffect(() => {
  const f = () => setOnline(navigator.onLine);
  window.addEventListener("online", f);
  window.addEventListener("offline", f);
  return () => { … };
}, []);
always consistent
const online = useSyncExternalStore(
  subscribe,
  () => navigator.onLine,
  () => true
);

When drawing can be interrupted (transitions, Suspense), the effect version can leave two components showing different values in the same frame. That is exactly what this hook prevents.

Pitfall getSnapshot has to return stable values

If the function returns a new object every call (() => ({ w: window.innerWidth })), React redraws forever. Return a simple value, or cache the object.

Reach for it when …
  • +

    Subscribing to browser values: navigator.onLine, matchMedia, localStorage

  • +

    Plugging in a store file that lives outside React

  • +

    When you are building a state library

Skip it when …
  • Ordinary component state – that is what useState is for

  • Server data – there are query libraries for that

Does it stick?

3 questions on this lesson. Wrong answers show up in your stats.

Hirefullstack

Need React firepower on your team?

We have been building React and Next.js applications for clients across Germany for years – as a single expert, as reinforcement for an existing team, or as a complete Scrum team.

Talk about your project →