网站空间的选择,企业logo设计用什么软件,苏州做网站的专业公司有哪些,苏州企业网站设计开发1. 基本概念
useSyncExternalStore 是 React 18 引入的一个 Hook#xff0c;用于订阅外部数据源#xff0c;确保在并发渲染下数据的一致性。它主要用于#xff1a;
订阅浏览器 API#xff08;如 window.width#xff09;订阅第三方状态管理库订阅任何外部数据源
1.1 基…1. 基本概念
useSyncExternalStore 是 React 18 引入的一个 Hook用于订阅外部数据源确保在并发渲染下数据的一致性。它主要用于
订阅浏览器 API如 window.width订阅第三方状态管理库订阅任何外部数据源
1.1 基本语法
const state useSyncExternalStore(subscribe, // 订阅函数getSnapshot, // 获取当前状态的函数getServerSnapshot // 可选服务端渲染时获取状态的函数
);2. 基础示例
2.1 订阅窗口大小变化
getSnapshot 是一个函数用于返回当前浏览器窗口的宽度和高度。window.innerWidth 和 window.innerHeight 分别获取浏览器窗口的宽度和高度。 该函数返回一个对象包含 width 和 height 两个属性。 subscribe 函数接受一个回调函数 callback并将其作为事件监听器绑定到 resize 事件上。 每当浏览器窗口的尺寸发生变化时resize 事件会触发进而调用 callback。 subscribe 函数还返回一个清理函数return () window.removeEventListener(‘resize’, callback)用于在组件卸载时移除事件监听器防止内存泄漏。 当callback回调触发的时候就会触发组件更新
function useWindowSize() {const getSnapshot () ({width: window.innerWidth,height: window.innerHeight});const subscribe (callback) {window.addEventListener(resize, callback);return () window.removeEventListener(resize, callback);};return useSyncExternalStore(subscribe, getSnapshot);
}function WindowSizeComponent() {const { width, height } useWindowSize();return (divWindow size: {width} x {height}/div);
}2.2 订阅浏览器在线状态
function useOnlineStatus() {const getSnapshot () navigator.onLine;const subscribe (callback) {window.addEventListener(online, callback);window.addEventListener(offline, callback);return () {window.removeEventListener(online, callback);window.removeEventListener(offline, callback);};};return useSyncExternalStore(subscribe, getSnapshot);
}function OnlineStatusComponent() {const isOnline useOnlineStatus();return (divStatus: {isOnline ? 在线 : 离线}/div);
}3. 进阶用法
3.1 创建自定义存储
useTodoStore 是一个自定义 Hook它使用了 useSyncExternalStore 来同步外部存储即 todoStore的状态。 todoStore.subscribe订阅状态更新。每当 todoStore 中的状态变化时useSyncExternalStore 会触发重新渲染。 todoStore.getSnapshot获取当前的状态快照在此返回的对象包含 todos 和 filter。
function createStore(initialState) {let state initialState;const listeners new Set();return {subscribe(listener) {listeners.add(listener);return () listeners.delete(listener);},getSnapshot() {return state;},setState(newState) {state newState;listeners.forEach(listener listener());}};
}const todoStore createStore({todos: [],filter: all
});function useTodoStore() {return useSyncExternalStore(todoStore.subscribe,todoStore.getSnapshot);
}function TodoList() {const { todos, filter } useTodoStore();return (ul{todos.filter(todo filter all || todo.completed (filter completed)).map(todo (li key{todo.id}{todo.text}/li))}/ul);
}3.2 与服务端渲染集成
function useSharedState(initialState) {const store useMemo(() createStore(initialState), [initialState]);// 提供服务端快照const getServerSnapshot () initialState;return useSyncExternalStore(store.subscribe,store.getSnapshot,getServerSnapshot);
}3.3 订阅 WebSocket 数据
function useWebSocketData(url) {const [store] useState(() {let data null;const listeners new Set();const ws new WebSocket(url);ws.onmessage (event) {data JSON.parse(event.data);listeners.forEach(listener listener());};return {subscribe(listener) {listeners.add(listener);return () {listeners.delete(listener);if (listeners.size 0) {ws.close();}};},getSnapshot() {return data;}};});return useSyncExternalStore(store.subscribe, store.getSnapshot);
}function LiveDataComponent() {const data useWebSocketData(wss://api.example.com/live);if (!data) return divLoading.../div;return (divh2实时数据/h2pre{JSON.stringify(data, null, 2)}/pre/div);
}4. 性能优化
4.1 选择性订阅
function useStoreSelector(selector) {const store useContext(StoreContext);const getSnapshot useCallback(() {return selector(store.getSnapshot());}, [store, selector]);return useSyncExternalStore(store.subscribe,getSnapshot);
}// 使用示例
function TodoCounter() {const count useStoreSelector(state state.todos.length);return divTotal todos: {count}/div;
}4.2 避免不必要的更新
function createStoreWithSelector(initialState) {let state initialState;const listeners new Map();return {subscribe(listener, selector) {const wrappedListener () {const newSelectedValue selector(state);if (newSelectedValue ! selector(previousState)) {listener();}};listeners.set(listener, wrappedListener);return () listeners.delete(listener);},getSnapshot() {return state;},setState(newState) {const previousState state;state newState;listeners.forEach(listener listener());}};
}5. 实际应用场景
5.1 主题切换系统
function createThemeStore() {let theme light;const listeners new Set();return {subscribe(listener) {listeners.add(listener);return () listeners.delete(listener);},getSnapshot() {return theme;},toggleTheme() {theme theme light ? dark : light;listeners.forEach(listener listener());}};
}const themeStore createThemeStore();function useTheme() {return useSyncExternalStore(themeStore.subscribe,themeStore.getSnapshot);
}function ThemeToggle() {const theme useTheme();return (button onClick{() themeStore.toggleTheme()}Current theme: {theme}/button);
}5.2 表单状态管理
function createFormStore(initialValues) {let values initialValues;const listeners new Set();return {subscribe(listener) {listeners.add(listener);return () listeners.delete(listener);},getSnapshot() {return values;},updateField(field, value) {values { ...values, [field]: value };listeners.forEach(listener listener());},reset() {values initialValues;listeners.forEach(listener listener());}};
}function useForm(initialValues) {const [store] useState(() createFormStore(initialValues));return useSyncExternalStore(store.subscribe,store.getSnapshot);
}function Form() {const formData useForm({ name: , email: });return (forminputvalue{formData.name}onChange{e formStore.updateField(name, e.target.value)}/inputvalue{formData.email}onChange{e formStore.updateField(email, e.target.value)}//form);
}6. 注意事项 保持一致性 subscribe 函数应该返回清理函数getSnapshot 应该返回不可变的数据 避免频繁更新 考虑使用节流或防抖实现选择性订阅机制 服务端渲染 提供 getServerSnapshot确保服务端和客户端状态同步 内存管理 及时清理订阅避免内存泄漏
通过合理使用 useSyncExternalStore我们可以安全地订阅外部数据源并确保在 React 并发渲染下的数据一致性。这个 Hook 特别适合需要与外部系统集成的场景。 还可以用来实现浏览器localStrorage的持久化存储