External Store Integration with useSyncExternalStore
`useSyncExternalStore` provides React-safe subscriptions to state maintained outside the component tree. It lets a component read an external store snapshot and re-render when the store reports changes.
An external store is state whose source of truth lives outside React, such as a custom event emitter, browser API, or shared state library. React needs a consistent way to subscribe to that state so updates participate correctly in rendering.
`useSyncExternalStore(subscribe, getSnapshot)` connects a component to such a store. `subscribe` registers a callback for store changes, while `getSnapshot` returns the current immutable snapshot that React should render.
React compares successive snapshots to determine whether the component needs to update, so `getSnapshot` should return a cached value when the underlying store has not changed. Returning a newly created object on every call can cause unnecessary renders and can violate the expected snapshot semantics.
For server rendering, an optional third argument, `getServerSnapshot`, supplies the snapshot React should use during server rendering and hydration. The server and initial client snapshots need to represent compatible state so hydration can proceed consistently.
A common pattern is to keep mutation logic inside the external store and expose a small subscription API. Components then remain consumers of the store rather than manually coordinating event listeners and synchronization themselves.
Key points
- Use `useSyncExternalStore` when the source of truth lives outside React state.
- `subscribe` tells React how to listen for store changes.
- `getSnapshot` returns the current renderable store state.
- Snapshots should be stable and cached when the store has not changed.
- Use `getServerSnapshot` when server rendering requires an initial external-store value.
Interview questions
What problem does `useSyncExternalStore` solve?
It connects React components to state managed outside React. The component provides a subscription function and a way to read the current snapshot. React can then re-render when the external store changes without the component manually mirroring the store into local state.
What are the roles of `subscribe` and `getSnapshot`?
`subscribe` tells React how to register a callback that should run when the external store changes, and it must provide a way to unsubscribe. `getSnapshot` returns the store state that React should use for rendering. React can call the snapshot function when it needs to determine the current value.
Why must `getSnapshot` return a cached result when the store has not changed?
React relies on snapshot identity to determine whether the external state has changed. If every call creates a fresh object, React can observe a different value even though the underlying store is unchanged. That can cause unnecessary updates and can lead to an unstable subscription/rendering pattern. The store should therefore cache or otherwise preserve the snapshot until its underlying state changes.
When would you provide `getServerSnapshot`?
You provide `getServerSnapshot` when the component can be rendered on the server. It supplies the snapshot used during server rendering and the initial hydration step. The value needs to correspond to the state expected by the client at hydration so React can maintain a consistent initial render. This is particularly important when the external source has different server and browser environments.
How would you design an external store for use with `useSyncExternalStore`?
I would keep the store's mutable source of truth private and expose `subscribe`, `getSnapshot`, and mutation operations. Updates would change the store state and notify every active subscriber. I would ensure that snapshots remain referentially stable until the relevant state changes. If the application uses server rendering, I would also define a deterministic server snapshot and make the hydration state compatible with it.