Volume 3

Q162: External Stores and useSyncExternalStore

Difficulty: SeniorFrequency: MediumAnswer time: 8-12 minutes

What Interviewers Want To Evaluate

This question checks whether you know how React safely reads state owned outside React. Interviewers want external store examples, subscription contracts, snapshots, tearing, concurrent rendering safety, server snapshots, selector patterns, and when external stores are better than Context or local state.

Senior answers should explain why React needs a formal bridge to non-React state.

Short Interview Answer

An external store is state managed outside React, such as a custom event store, browser API, websocket cache, Redux store, Zustand store, or media query subscription. useSyncExternalStore lets React subscribe to that store and read a consistent snapshot during rendering. It exists so external mutable data can work correctly with concurrent rendering and hydration. The store must provide a subscribe function and a snapshot getter.

Detailed Interview Answer

React state is owned by React. External store state is not.

Examples:

Redux store
Zustand store
browser online status
media query match state
websocket-backed cache
local storage wrapper
custom observable object

React needs a way to subscribe and read a snapshot safely.

const value = useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);

The hook tells React:

how to subscribe to changes
how to read the current client snapshot
how to read a server snapshot during hydration

Minimal Example

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 getServerSnapshot() {
  return true;
}

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

Now React can rerender consumers when the external value changes.

Why Not useEffect and useState?

You can often wrap an external subscription with useEffect and useState.

useEffect(() => {
  return store.subscribe(() => setValue(store.get()));
}, []);

But this has issues:

initial render may read stale data
server rendering can mismatch
concurrent rendering can see inconsistent snapshots
manual subscriptions are repeated
tearing can occur when state changes during render work

useSyncExternalStore gives React the correct contract.

Snapshot Contract

getSnapshot should return the same value if the store has not changed.

If it returns a new object every call, React can think the snapshot changed repeatedly.

Bad:

function getSnapshot() {
  return { user: store.user };
}

Better:

function getSnapshot() {
  return store.getCachedSnapshot();
}

The store should cache or return stable references when data is unchanged.

Subscribe Contract

subscribe receives a callback and returns an unsubscribe function.

function subscribe(callback) {
  listeners.add(callback);
  return () => listeners.delete(callback);
}

The store calls listeners after its internal state changes.

The callback does not pass the new value. React will call getSnapshot.

Tearing

Tearing means different parts of the UI see different versions of external state during the same render.

Concurrent rendering makes this easier to hit if external mutable data is read directly.

useSyncExternalStore helps React detect store changes and restart rendering with a consistent snapshot.

Server Snapshot

For server rendering, getServerSnapshot should return the snapshot used for hydration.

useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);

If the server and client snapshots do not match, hydration can show incorrect initial UI.

For browser-only state, choose a conservative server snapshot and update after hydration.

Selectors

Large stores often need selectors.

const userName = useStore((state) => state.user.name);

Selectors reduce rerenders when unrelated state changes.

The selector result should also be stable. Equality checks can help when deriving objects or arrays.

External Store vs Context

Context broadcasts provider value changes to consumers.

An external store can support granular subscriptions, selectors, middleware, persistence, devtools, and framework-independent state.

Choose external stores when:

state is shared across distant trees
updates are frequent
subscribers need selectors
state has persistence or undo
non-React code also reads or writes it

Choose Context when the value is ambient and stable.

Common Mistakes

A common mistake is reading external mutable state directly during render without subscription.

Another mistake is returning a new snapshot object on every call.

Another mistake is subscribing in every component with inconsistent cleanup.

Another mistake is using an external store for purely local component state.

Senior Trade-Offs

External stores can improve performance and organization. They also add contracts, tooling, and global coupling.

Senior engineers use external stores when ownership crosses component boundaries in a meaningful way, not because every piece of state deserves a central home.

Code or Design Example

function createCounterStore() {
  let state = { count: 0 };
  const listeners = new Set();

  return {
    getSnapshot: () => state,
    subscribe: (listener) => {
      listeners.add(listener);
      return () => listeners.delete(listener);
    },
    increment: () => {
      state = { count: state.count + 1 };
      listeners.forEach((listener) => listener());
    },
  };
}

The store owns state; React subscribes to it.

Debugging Workflow

When external store behavior is wrong:

verify subscribe cleanup
verify getSnapshot stability
check selector equality
check server snapshot
avoid direct mutable reads in render
profile subscriber rerenders
test rapid updates during navigation

Interview Framing

Define external stores, explain the subscribe and snapshot contract, then discuss concurrent safety, selectors, server rendering, and alternatives.

Revision Notes

useSyncExternalStore is React's official bridge for safely reading non-React state during render.

Key Takeaways

External state needs a reliable subscription and snapshot contract. Without that contract, React cannot safely coordinate rendering.

Follow-Up Questions

  1. What is an external store?
  2. What does useSyncExternalStore accept?
  3. Why does getSnapshot need stable references?
  4. What does subscribe return?
  5. What is tearing?
  6. Why is server snapshot important?
  7. When are selectors useful?
  8. When is Context enough?
  9. When is an external store better?
  10. What bugs happen when external state is read directly?

How I Would Answer This In A Real Interview

I would say external stores own state outside React, so React needs useSyncExternalStore to subscribe and read a consistent snapshot. I would emphasize stable snapshots, cleanup, selectors, hydration behavior, and choosing external stores only when shared ownership and granular subscriptions justify them.