React 18 added useSyncExternalStore, a hook that lets components read data from any source that lives outside the React tree—browser APIs, WebSockets, or third-party stores—without the visual glitches that plagued the old pattern of mirroring that data with useState and useEffect. If you’ve ever seen a UI flicker because part of it showed an old window size while another part already reflected the new one, this hook is the fix you’ve been waiting for.

Why external state needs a new hook

React components have always been able to subscribe to things that exist beyond their own scope: the window object, a Redux store, a WebSocket connection. The conventional approach was to set up a subscription inside a useEffect, push incoming values into local state via setState, and let React re-render. That works fine when React renders synchronously, but React 18 introduced concurrent rendering, where a component may be rendered multiple times before the browser actually paints. In that mode the “mirror-into-local-state” pattern can produce tearing—different parts of the UI reading different snapshots of the same external value during a single render cycle.

useSyncExternalStore was built to prevent tearing. It asks the external source for a snapshot (the current value) and for a subscribe function (how to be notified of changes). React calls subscribe when the component mounts and automatically unsubscribes on unmount. Whenever the snapshot returned by getSnapshot changes, React schedules a render that reads the same snapshot for the whole component tree, guaranteeing consistency.

The two required functions

Function What it does
subscribe Receives a callback that must be called whenever the external value changes. It returns an unsubscribe function that React will call on cleanup.
getSnapshot Returns the current value from the external source. It must be referentially stable—the same function object on every render—so React can compare snapshots correctly.

A minimal implementation for the browser’s online status looks like this:

function useOnlineStatus() {
  return useSyncExternalStore(
    (onChange) => {
      window.addEventListener('online', onChange);
      window.addEventListener('offline', onChange);
      return () => {
        window.removeEventListener('online', onChange);
        window.removeEventListener('offline', onChange);
      };
    },
    () => navigator.onLine
  );
}

When any component calls useOnlineStatus(), React will re-render it only when navigator.onLine actually flips, and every render will see the same value.

Rules that keep the hook from blowing up

  1. Return the smallest piece of data a component needs.
    If the external store holds a large object but a component only cares about one field, return just that field. Larger returns cause unnecessary renders.

  2. Memoise getSnapshot.
    If you recreate the function on every render, React treats it as a new source and may loop forever. Wrap it in useCallback or define it outside the component.

  3. Avoid returning fresh objects each call.
    Returning a new object (e.g., { count: store.getCount() }) creates a new reference on every render, making React think the snapshot changed and triggering an infinite render loop. Use primitives, strings, numbers, or memoised objects.

  4. Don’t use it for internal component state.
    useState is still the right tool for data that lives only inside the component. useSyncExternalStore adds overhead that isn’t needed for local state.

When to reach for it

  • Browser APIs – window size, media queries, navigator.onLine, battery status.
  • Framework-agnostic stores – Zustand, Redux, MobX, or any custom store that exposes a subscription API.
  • Mutable sources that update outside React – WebSocket messages, IndexedDB change events, Service Worker notifications.

If your data source already lives inside React (e.g., a parent component’s state), stick with useState or context.

What the community is saying

Early adopters report that useSyncExternalStore eliminates the flicker they saw when resizing windows in a concurrent-rendering setup. Some libraries have already switched their internal hooks to this API, promising more predictable behavior across React versions. The trade-off is a slightly higher mental load: developers must think about stability of the two functions and avoid returning new objects each call.

What to watch next

React ನ ಮುಂಬರುವ ಬಿಡುಗಡೆಗಳು useSyncExternalStore ಸುತ್ತಲಿನ ನಿಯಮಗಳನ್ನು ಇನ್ನಷ್ಟು ಬಿಗಿಗೊಳಿಸಬಹುದು, ಮತ್ತು ಬಹುಶಃ ಸಾಮಾನ್ಯ ಬ್ರೌಸರ್ APIಗಳಿಗಾಗಿ ಬಿಲ್ಟ್-ಇನ್ ಸಹಾಯಕಗಳನ್ನು (helpers) ಸೇರಿಸಬಹುದು. ಹಳೆಯ useEffect-mirroring ಮಾದರಿಯನ್ನು ನಿಲ್ಲಿಸುವ (deprecations) ಬಗ್ಗೆ ತಿಳಿಯಲು ಅಧಿಕೃತ React ಬ್ಲಾಗ್ ಅನ್ನು ಗಮನಿಸುತ್ತಿರಿ. ಈ ಮಧ್ಯೆ, ಈ hook ಸ್ಥಿರವಾಗಿದೆ ಮತ್ತು public API ನ ಭಾಗವಾಗಿದೆ, ಆದ್ದರಿಂದ ನೀವು ಅಸ್ತಿತ್ವದಲ್ಲಿರುವ external-state ಕೋಡ್ ಅನ್ನು ಸುರಕ್ಷಿತವಾಗಿ ರಿಫ್ಯಾಕ್ಟರ್ ಮಾಡಬಹುದು.

ಶೀಘ್ರ ಪರೀಕ್ಷೆ

window-size ಸಿಂಕಿಂಗ್, ಆನ್‌ಲೈನ್/ಆಫ್‌ಲೈನ್ ಪತ್ತೆ ಮತ್ತು ಒಂದು ಸರಳ Zustand store ಅನ್ನು ಪ್ರದರ್ಶಿಸುವ ಲೈವ್ ಡೆಮೊ https://usesyncexternalstore.vercel.app/ ನಲ್ಲಿ ಲಭ್ಯವಿದೆ. ಕಾಮೆಂಟ್‌ಗಳೊಂದಿಗೆ ಸಂಪೂರ್ಣವಾಗಿರುವ ಸೋರ್ಸ್ ಕೋಡ್ https://github.com/dev48v/usesyncexternalstore ನಲ್ಲಿ ಲಭ್ಯವಿದೆ.

ಮುಖ್ಯ ಅಂಶ: useSyncExternalStore ತನ್ನ ರೆಂಡರ್ ಸೈಕಲ್‌ನ ಹೊರಗೆ ಇರುವ ಯಾವುದೇ mutable ಡೇಟಾಕ್ಕೆ React ಗೆ ಒಂದು ನಂಬಿಕಾರ್ಹ ಸೇತುವೆಯನ್ನು ನೀಡುತ್ತದೆ, ಇದು tearing ಮತ್ತು ಅನಗತ್ಯ ರೆಂಡರ್‌ಗಳನ್ನು ತಡೆಯುತ್ತದೆ. ಇದನ್ನು ಎಕ್ಸ್‌ಟರ್ನಲ್ ಸೋರ್ಸ್‌ಗಳಿಗೆ ಅನ್ವಯಿಸಿ, snapshot ಅನ್ನು ಕನಿಷ್ಠ ಮತ್ತು ಸ್ಥಿರವಾಗಿರಿಸಿ, ಮತ್ತು consistency ಕಾಪಾಡುವ ಕಠಿಣ ಕೆಲಸವನ್ನು React ಮಾಡಲಿ.