useSyncExternalStore:同步 React 与 localStorage 的正确方式
发布: (2026年1月9日 GMT+8 12:00)
3 min read
原文: Dev.to
Source: Dev.to
Introduction
React 18 引入了一个低层次的 Hook,大多数开发者从未直接使用过,但几乎所有现代状态库都依赖它:useSyncExternalStore。
它是 React 官方连接组件与外部状态源的方式——这些状态存在于 React 之外,例如:
localStorage- Redux / Zustand store
- 浏览器 API
- WebSocket 数据
Why useSyncExternalStore?
在 React 18 之前,订阅外部 store 通常这样写:
useEffect(() => store.subscribe(forceUpdate), []);
这种模式在并发渲染下会出问题。useSyncExternalStore 通过让 React 控制以下内容来解决该问题:
- 订阅 更改
- 读取 当前值
- 安全触发 重新渲染
const value = useSyncExternalStore(
subscribe,
getSnapshot,
getServerSnapshot? // optional, for server‑side rendering
);
subscribe– React 如何监听更新getSnapshot– React 如何读取当前状态
当快照变化时,React 会自动重新渲染。
Creating a localStorage store
function createLocalStorageStore(key, initialValue) {
const listeners = new Set();
const getSnapshot = () => {
const data = localStorage.getItem(key);
return data ? JSON.parse(data) : initialValue;
};
const setValue = (value) => {
localStorage.setItem(key, JSON.stringify(value));
listeners.forEach((l) => l());
};
const subscribe = (listener) => {
listeners.add(listener);
const onStorage = (e) => {
if (e.key === key) listener();
};
window.addEventListener("storage", onStorage);
return () => {
listeners.delete(listener);
window.removeEventListener("storage", onStorage);
};
};
return { getSnapshot, setValue, subscribe };
}
Hook wrapper for external stores
import { useSyncExternalStore } from "react";
function useExternalStore(store) {
return useSyncExternalStore(
store.subscribe,
store.getSnapshot,
store.getSnapshot // same function for server snapshot if needed
);
}
Example: Counter synced with localStorage
const counterStore = createLocalStorageStore("counter", 0);
function Counter() {
const count = useExternalStore(counterStore);
return (
<>
Count: {count}
{/* The original snippet omitted the button element; kept as‑is */}
counterStore.setValue(count + 1)}>+
</>
);
}
现在计数器状态是:
- 持久化(保存在
localStorage中) - 共享 于多个组件之间
- 跨标签页同步,通过
storage事件实现 - 并发安全,得益于
useSyncExternalStore
When to use useSyncExternalStore
- 状态存在于 React 之外(例如浏览器存储、外部 store、WebSocket 数据)。
- 多个组件需要 共享 同一数据。
- 正在构建 store、持久化层 或 库,供其他组件使用。
对于普通的组件本地状态,仍然使用 useState。useState 管理 React 自身的状态,而 useSyncExternalStore 用于将 React 与外部世界连接。如果你要构建的东西超出本地组件状态,这个 Hook 就是基础。