React  

Understanding useSyncExternalStore in React

Introduction

useSyncExternalStore is a React Hook introduced in React 18 to safely subscribe to external stores in concurrent rendering environments. It ensures that your component reads consistent data and avoids tearing issues when React renders components multiple times.

This hook is mainly used when integrating React with:

  • Custom state management libraries

  • Redux-like stores

  • Browser APIs

  • External data sources outside React

It provides a reliable way to subscribe to external data while supporting concurrent features.

Why useSyncExternalStore Is Needed

Before React 18, developers commonly used useEffect and useState to subscribe to external stores. However, this approach could cause inconsistencies during concurrent rendering.

useSyncExternalStore solves this by:

  • Ensuring the snapshot is always consistent

  • Supporting server-side rendering (SSR)

  • Preventing visual tearing

  • Working correctly with concurrent rendering

Syntax

const state = useSyncExternalStore(
  subscribe,
  getSnapshot,
  getServerSnapshot?
);

Parameters

  1. subscribe
    A function that registers a callback and returns an unsubscribe function.

  2. getSnapshot
    Returns the current value from the store.

  3. getServerSnapshot (optional)
    Used for server-side rendering.

Example: Creating a Simple Custom Store

Let’s build a small counter store outside React.

Step 1: Create the Store

// counterStore.js

let count = 0;
const listeners = new Set();

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

Step 2: Use useSyncExternalStore in a Component

import React, { useSyncExternalStore } from "react";
import { counterStore } from "./counterStore";

function Counter() {
  const count = useSyncExternalStore(
    counterStore.subscribe,
    counterStore.getSnapshot
  );

  return (
    <div>
      <h2>Count: {count}</h2>
      <button onClick={counterStore.increment}>
        Increment
      </button>
    </div>
  );
}

export default Counter;

Example: Using with Redux

If you're using Redux, modern versions internally use useSyncExternalStore. However, if implementing manually:

const state = useSyncExternalStore(
  store.subscribe,
  store.getState
);

This ensures safe subscription in concurrent mode.

Server-Side Rendering Example

const value = useSyncExternalStore(
  store.subscribe,
  store.getSnapshot,
  () => initialServerValue
);

The third parameter ensures the correct snapshot is used during SSR.

When to Use useSyncExternalStore

Use it when:

  • You are building a custom state management solution

  • You are integrating a non-React store

  • You need concurrent-safe subscriptions

  • You are working on library-level code

Avoid it for normal component state. For most use cases, useState and useReducer are sufficient.

Common Mistakes

  1. Returning a new object in getSnapshot every time
    This causes unnecessary re-renders.

  2. Not properly cleaning up in subscribe
    Always return an unsubscribe function.

  3. Using it for local state
    It is meant for external stores only.

Conclusion

useSyncExternalStore is a low-level React Hook designed for safely subscribing to external data sources in React 18 and beyond. It ensures consistency during concurrent rendering and supports server-side rendering seamlessly.

While most applications do not need to use it directly, it becomes essential when building custom state management systems or integrating external libraries. Understanding how it works gives deeper insight into how React handles synchronization and rendering under the hood.