React中的useSyncExternalStore使用

发布于:2025-05-14 ⋅ 阅读:(12) ⋅ 点赞:(0)

官方的解释是useSyncExternalStore 是一个让你订阅外部 store 的 React Hook。😄官方就爱打马虎眼,这样说随能一下子明白它的作用,接下来我们就来仔细的讲解下它的作用和应用场景。

useSyncExternalStore 作为 React 18 引入的一个 Hook,主要用于订阅外部数据源,确保在并发渲染下数据的一致性。它主要用于:

  • 订阅浏览器 API(如 window.width)
  • 订阅第三方状态管理库
  • 订阅任何外部数据源

直接上例子:

  • 基本语法
const state = useSyncExternalStore(
  subscribe,  // 订阅函数
  getSnapshot, // 获取当前状态的函数
  getServerSnapshot // 可选:服务端渲染时获取状态的函数
);
  • 实战 浏览器网络状态
//useOnlineStatus hooks 
import { useSyncExternalStore } from 'react';

export function useOnlineStatus() {
  const isOnline = useSyncExternalStore(subscribe, getSnapshot);
  return isOnline;
}

function getSnapshot() {
  return navigator.onLine;
}

function subscribe(callback) {
  window.addEventListener('online', callback);
  window.addEventListener('offline', callback);
  return () => {
    window.removeEventListener('online', callback);
    window.removeEventListener('offline', callback);
  };
}
  • 实战浏览器窗口宽高
// useWindowSize hooks
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);
}

// 组建中 hooks使用 
function NavComponent() {
  const { width, height } = useWindowSize();

  return (
    <div>
      Window size: {width} x {height}
    </div>
  );
}
  • 实战 切换主题
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>
  );
}

 

注意事项

  1. 保持一致性

    • subscribe 函数应该返回清理函数
    • getSnapshot 应该返回不可变的数据
  2. 避免频繁更新

    • 考虑使用节流或防抖
    • 实现选择性订阅机制
  3. 服务端渲染

    • 提供 getServerSnapshot
    • 确保服务端和客户端状态同步
  4. 内存管理

    • 及时清理订阅
    • 避免内存泄漏