JAVASCRIPT
Integrating External Mutable Stores with useSyncExternalStore
Learn how to use React 18's useSyncExternalStore hook to efficiently subscribe to and read values from external, mutable data sources, ensuring automatic re-renders.
import React, { useSyncExternalStore, useState, useEffect } from 'react';
// A simple external mutable store
const createCounterStore = () => {
let count = 0;
const listeners = new Set();
return {
getSnapshot: () => count, // Returns the current state
subscribe: (listener) => { // Subscribes a listener
listeners.add(listener);
return () => listeners.delete(listener); // Unsubscribe function
},
increment: () => {
count++;
listeners.forEach((l) => l()); // Notify all listeners
},
decrement: () => {
count--;
listeners.forEach((l) => l());
},
};
};
const counterStore = createCounterStore();
function CounterDisplay() {
// useSyncExternalStore takes:
// 1. A subscribe function
// 2. A getSnapshot function (for client-side)
// 3. An optional getServerSnapshot function (for SSR)
const count = useSyncExternalStore(counterStore.subscribe, counterStore.getSnapshot);
return (
<div>
<h3>External Counter Store</h3>
<p>Current Count: {count}</p>
<button onClick={counterStore.increment}>Increment</button>
<button onClick={counterStore.decrement}>Decrement</button>
</div>
);
}
export default CounterDisplay;
How it works: Introduced in React 18, `useSyncExternalStore` is designed for efficiently reading from and subscribing to external mutable data sources (like state management libraries, browser APIs, or custom observable stores). It helps solve the "tearing" problem that can occur when external state changes between React snapshotting and committing, ensuring that React components always read a consistent snapshot of the external store. It requires a `subscribe` function to register listeners and a `getSnapshot` function to read the current state.