精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

深入理解useSyncExternalStore - 從原理到實戰的完整指南

開發 前端
在React的Hook家族中,useSyncExternalStore可能是最容易被忽略的一個。不是因為它不重要,而是因為大多數開發者在日常開發中很少遇到需要它的場景。但是,當你真正需要它的時候,它會成為你的救星。更重要的是,理解這個Hook能讓你對React的工作原理有更深層的認識。

一個被忽視的實用Hook

在React的Hook家族中,useSyncExternalStore可能是最容易被忽略的一個。

不是因為它不重要,而是因為大多數開發者在日常開發中很少遇到需要它的場景。

但是,當你真正需要它的時候,它會成為你的救星。更重要的是,理解這個Hook能讓你對React的工作原理有更深層的認識。

今天我們就來深入探討這個Hook:它解決了什么問題,如何使用,以及為什么掌握它對React開發者很有價值。

問題背景:React外部數據同步的挑戰

常見的困惑場景

在實際開發中,你可能遇到過這樣的情況:

// 場景:使用全局變量存儲數據
let globalCounter = 0;

function Counter() {
const increment = () => {
    globalCounter++;
    console.log('Counter updated:', globalCounter); // 確實更新了
    // 但是組件不會重新渲染!
  };

return (
    <div>
      <p>當前計數: {globalCounter}</p>
      <button onClick={increment}>增加</button>
    </div>
  );
}

或者試圖用useRef來解決:

function Counter() {
const counterRef = useRef(0);

const increment = () => {
    counterRef.current++;
    // 數據更新了,但UI依然不會刷新
  };

return (
    <div>
      <p>當前計數: {counterRef.current}</p>
      <button onClick={increment}>增加</button>
    </div>
  );
}

問題根源:React的響應式更新機制

React并不會自動監聽所有變量的變化。它只會在特定的"信號"觸發時才重新渲染組件:

  • setState調用
  • useReducer的dispatch
  • Context值變化
  • 父組件重新渲染

對于外部數據(不受React狀態管理的數據),React需要一種機制來感知變化并觸發更新。

這就是useSyncExternalStore存在的意義。

useSyncExternalStore詳解:橋接外部世界與React

基本API和工作原理

const data = useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot?)

參數說明:

  • subscribe:訂閱函數,接收一個回調函數,當外部數據變化時調用這個回調
  • getSnapshot:獲取當前數據快照的函數
  • getServerSnapshot:可選,SSR時獲取服務端快照

核心思想:

  1. 通過subscribe讓React知道如何監聽外部數據變化
  2. 通過getSnapshot讓React獲取最新的數據
  3. 當外部數據變化時,訂閱的回調函數會通知React重新渲染

實戰案例:構建一個簡單的計數器Store

第一步:創建外部Store

// counterStore.js
class CounterStore {
constructor() {
    this.count = 0;
    this.listeners = [];
  }

// 獲取當前值
  getSnapshot = () => {
    returnthis.count;
  }

// 訂閱變化
  subscribe = (listener) => {
    this.listeners.push(listener);
    // 返回取消訂閱的函數
    return() => {
      this.listeners = this.listeners.filter(l => l !== listener);
    };
  }

// 觸發變化通知
  emitChange = () => {
    this.listeners.forEach(listener => listener());
  }

// 業務方法
  increment = () => {
    this.count++;
    this.emitChange(); // 關鍵:通知React更新
  }

  decrement = () => {
    this.count--;
    this.emitChange();
  }

  reset = () => {
    this.count = 0;
    this.emitChange();
  }
}

exportconst counterStore = new CounterStore();

第二步:在React組件中使用

import { useSyncExternalStore } from'react';
import { counterStore } from'./counterStore';

function Counter() {
// 連接外部Store
const count = useSyncExternalStore(
    counterStore.subscribe,
    counterStore.getSnapshot
  );

return (
    <div>
      <h2>計數器: {count}</h2>
      <button onClick={counterStore.increment}>+1</button>
      <button onClick={counterStore.decrement}>-1</button>
      <button onClick={counterStore.reset}>重置</button>
    </div>
  );
}

// 多個組件可以同時使用同一個Store
function CounterDisplay() {
const count = useSyncExternalStore(
    counterStore.subscribe,
    counterStore.getSnapshot
  );

return<div>當前計數: {count}</div>;
}

現在,點擊任何按鈕都會正確地更新所有使用該Store的組件!

進階實戰:更復雜的應用場景

場景1:瀏覽器窗口尺寸監聽

// windowSizeStore.js
class WindowSizeStore {
constructor() {
    this.size = {
      width: typeofwindow !== 'undefined' ? window.innerWidth : 0,
      height: typeofwindow !== 'undefined' ? window.innerHeight : 0
    };
    this.listeners = [];
    
    if (typeofwindow !== 'undefined') {
      window.addEventListener('resize', this.handleResize);
    }
  }

  handleResize = () => {
    this.size = {
      width: window.innerWidth,
      height: window.innerHeight
    };
    this.emitChange();
  }

  getSnapshot = () =>this.size;

  subscribe = (listener) => {
    this.listeners.push(listener);
    return() => {
      this.listeners = this.listeners.filter(l => l !== listener);
    };
  }

  emitChange = () => {
    this.listeners.forEach(listener => listener());
  }

  cleanup = () => {
    if (typeofwindow !== 'undefined') {
      window.removeEventListener('resize', this.handleResize);
    }
  }
}

exportconst windowSizeStore = new WindowSizeStore();

// 使用
function WindowInfo() {
const { width, height } = useSyncExternalStore(
    windowSizeStore.subscribe,
    windowSizeStore.getSnapshot
  );

return (
    <div>
      窗口尺寸: {width} x {height}
    </div>
  );
}

場景2:本地存儲同步

// localStorageStore.js
class LocalStorageStore {
constructor(key, defaultValue = null) {
    this.key = key;
    this.defaultValue = defaultValue;
    this.listeners = [];
    
    // 監聽其他標簽頁的存儲變化
    if (typeofwindow !== 'undefined') {
      window.addEventListener('storage', this.handleStorageChange);
    }
  }

  handleStorageChange = (e) => {
    if (e.key === this.key) {
      this.emitChange();
    }
  }

  getSnapshot = () => {
    if (typeofwindow === 'undefined') returnthis.defaultValue;
    
    try {
      const item = localStorage.getItem(this.key);
      return item ? JSON.parse(item) : this.defaultValue;
    } catch {
      returnthis.defaultValue;
    }
  }

  subscribe = (listener) => {
    this.listeners.push(listener);
    return() => {
      this.listeners = this.listeners.filter(l => l !== listener);
    };
  }

  emitChange = () => {
    this.listeners.forEach(listener => listener());
  }

  setValue = (value) => {
    try {
      localStorage.setItem(this.key, JSON.stringify(value));
      this.emitChange();
    } catch (error) {
      console.error('Failed to save to localStorage:', error);
    }
  }

  removeValue = () => {
    localStorage.removeItem(this.key);
    this.emitChange();
  }
}

// 創建自定義Hook
exportfunction useLocalStorage(key, defaultValue) {
const store = useMemo(
    () =>new LocalStorageStore(key, defaultValue),
    [key, defaultValue]
  );

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

return [value, store.setValue, store.removeValue];
}

// 使用示例
function UserPreferences() {
const [theme, setTheme] = useLocalStorage('theme', 'light');

return (
    <div>
      <p>當前主題: {theme}</p>
      <button onClick={() => setTheme(theme === 'light' ? 'dark' : 'light')}>
        切換主題
      </button>
    </div>
  );
}

與現有方案的對比

vs useState/useReducer

  • 適用場景:useSyncExternalStore適合需要在多個組件間共享的外部數據
  • 性能考慮:避免了prop drilling,減少不必要的重新渲染
  • 數據源:可以是任何外部數據源,不限于React生態

vs Context API

  • 復雜度:useSyncExternalStore實現更簡單,不需要Provider包裝
  • 性能:更精確的更新控制,只有真正使用數據的組件才會重新渲染
  • 靈活性:可以輕松集成非React數據源

vs 第三方狀態管理庫

  • 輕量級:不需要額外依賴,React內置
  • 學習成本:理解原理后使用簡單
  • 定制化:完全控制數據結構和更新邏輯

最佳實踐和注意事項

1. Store設計原則

class GoodStore {
constructor() {
    this.data = initialData;
    this.listeners = []; // 或者使用Set
  }

// ? 返回不可變數據
  getSnapshot = () => {
    returnthis.data; // 確保是不可變的
  }

// ? 標準的訂閱模式
  subscribe = (listener) => {
    this.listeners.push(listener);
    return() => {
      this.listeners = this.listeners.filter(l => l !== listener);
    };
  }

// ? 所有修改操作都要通知更新
  updateData = (newData) => {
    this.data = newData;
    this.emitChange(); // 不要忘記這一步
  }
}

2. 性能優化技巧

// ? 使用useMemo避免重復創建Store實例
function useCustomStore() {
const store = useMemo(() =>new MyStore(), []);

return useSyncExternalStore(
    store.subscribe,
    store.getSnapshot
  );
}

// ? 選擇性訂閱,只訂閱需要的數據片段
function useUserName() {
return useSyncExternalStore(
    userStore.subscribe,
    () => userStore.getSnapshot().name // 只關心name字段
  );
}

3. 錯誤處理

class RobustStore {
  getSnapshot = () => {
    try {
      returnthis.data;
    } catch (error) {
      console.error('Store snapshot error:', error);
      returnthis.fallbackData;
    }
  }

  subscribe = (listener) => {
    try {
      this.listeners.push(listener);
      return() => {
        this.listeners = this.listeners.filter(l => l !== listener);
      };
    } catch (error) {
      console.error('Store subscription error:', error);
      return() => {}; // 返回空的清理函數
    }
  }
}

何時使用useSyncExternalStore?

適合的場景

  • 需要集成外部數據源(WebSocket、localStorage、瀏覽器API等)
  • 多個組件需要共享同一份數據且需要實時同步
  • 需要精確控制何時觸發React重新渲染
  • 構建輕量級的狀態管理解決方案

不適合的場景

  • 簡單的組件內部狀態(用useState就好)
  • 已經有成熟的狀態管理方案且工作良好
  • 數據不需要在組件間共享
  • 團隊對React Hook不夠熟悉

總結

useSyncExternalStore是React提供的一個強大而靈活的Hook,它為我們提供了:

  1. 原理透明:清晰地展示了React響應式更新的機制
  2. 集成能力:輕松集成任何外部數據源到React應用中
  3. 性能控制:精確控制何時觸發重新渲染
  4. 實現簡單:相比復雜的狀態管理庫,實現和理解都更簡單

雖然在日常開發中可能不會頻繁使用,但理解和掌握這個Hook能讓你:

  • 更深入地理解React的工作原理
  • 在特殊場景下有更好的解決方案
  • 閱讀和理解狀態管理庫的源碼時更得心應手

下次遇到需要集成外部數據源的場景時,不妨考慮使用useSyncExternalStore,你可能會發現它比你想象的更有用。

責任編輯:武曉燕 來源: 前端達人
相關推薦

2025-09-08 07:14:25

2025-07-28 07:21:33

2025-10-27 01:22:00

HTTP接口API

2022-01-14 12:28:18

架構OpenFeign遠程

2025-08-26 04:55:00

2022-11-04 09:43:05

Java線程

2024-03-12 00:00:00

Sora技術數據

2022-09-05 08:39:04

kubernetesk8s

2021-03-10 10:55:51

SpringJava代碼

2024-11-01 08:57:07

2020-08-10 18:03:54

Cache存儲器CPU

2024-04-15 00:00:00

技術Attention架構

2022-06-01 21:23:12

ELKLogstash底層

2024-02-23 16:10:29

KubernetesPrometheus開源

2023-09-19 22:47:39

Java內存

2020-03-26 16:40:07

MySQL索引數據庫

2022-09-26 08:01:31

線程LIFO操作方式

2019-07-01 13:34:22

vue系統數據

2023-10-13 13:30:00

MySQL鎖機制

2022-09-05 22:22:00

Stream操作對象
點贊
收藏

51CTO技術棧公眾號

神马影视一区二区| 自由的xxxx在线视频| 亚洲国产免费| 亚洲精品自产拍| 黄色免费观看视频网站| 黄色大片在线免费观看| 麻豆精品国产传媒mv男同| 欧美成人精品三级在线观看| 国产伦精品一区二区免费| 韩国成人动漫| 最近日韩中文字幕| 99热在线播放| 国产又粗又猛又黄视频| 欧美hentaied在线观看| 精品久久五月天| 男女曰b免费视频| 1区2区3区在线视频| 久久午夜色播影院免费高清| 国产一区二区在线免费视频| 国产亚洲精品久久久久久打不开 | 国产一区二区三区四区三区四| 日韩高清av在线| 亚洲欧美天堂在线| 深夜成人在线| 亚洲激情图片一区| 日本一区精品| 可以免费观看的毛片| 日本特黄久久久高潮| 久久久久久久一区二区| 欧美日韩国产黄色| 欧美变态挠脚心| 日韩一区二区三区视频| 一区二区三区国产免费| 多野结衣av一区| 国产精品激情偷乱一区二区∴| 精品国产一区二区三区久久久久久| 亚洲一级在线播放| 久久久国产精品一区二区中文| 欧美贵妇videos办公室| 国产精品一区二区亚洲| 蜜桃一区二区| 亚洲国产精品福利| 免费黄视频在线观看| 国产福利91精品一区二区| 欧美性猛交xxxx乱大交蜜桃| 中文精品无码中文字幕无码专区| av播放在线| 国产欧美一区视频| 免费国产一区| 天天干天天插天天操| 国产成人免费av在线| 成人免费视频97| 中文字幕 欧美激情| 久久夜色精品| 日本精品一区二区三区在线播放视频| 免费在线视频观看| 综合在线一区| 伦理中文字幕亚洲| 中文字幕亚洲欧美日韩| 99久久99久久精品国产片果冰| 有码中文亚洲精品| 中文字幕免费在线看线人动作大片| 青青一区二区| 亚洲精品久久久久中文字幕欢迎你| 人妻互换一二三区激情视频| 免费观看亚洲视频大全| 日韩欧美成人一区二区| 4438x全国最大成人| 麻豆精品国产| 精品国产乱码久久久久久免费| 日韩大尺度视频| aaa国产精品视频| 亚洲韩国欧洲国产日产av| 影音先锋人妻啪啪av资源网站| 精品淫伦v久久水蜜桃| 亚洲国产精品99| 99久久人妻无码中文字幕系列| 天堂成人娱乐在线视频免费播放网站| 日韩精品免费视频| b站大片免费直播| 郴州新闻综合频道在线直播| 日韩最新免费不卡| 亚洲欧美一区二区三区四区五区| 亚洲视频一二| 日本伊人精品一区二区三区介绍| 无码久久精品国产亚洲av影片| 免费看精品久久片| 91精品国自产在线观看| 日韩一级在线播放| 国产调教视频一区| 欧美 另类 交| 国产高清自产拍av在线| 在线观看区一区二| 999热精品视频| 风间由美性色一区二区三区四区| 亚洲乱码国产乱码精品精| 网爆门在线观看| 欧美日韩综合| 国产成+人+综合+亚洲欧洲| 中文无码av一区二区三区| 国产美女久久久久| 免费日韩av电影| 快射av在线播放一区| 亚洲国产精品综合小说图片区| 免费观看精品视频| 99久久99九九99九九九| 日韩高清av一区二区三区| 少妇高潮惨叫久久久久| 在线欧美三区| 国产专区欧美专区| 香蕉视频免费看| 中文字幕一区二区三区色视频 | 人妻 日韩 欧美 综合 制服| 欧美军人男男激情gay| 欧美国产日韩免费| 国产精品国产精品国产| 波多野结衣在线一区| 亚洲精品中文字幕在线| 黄在线观看免费网站ktv| 欧美日韩高清影院| 右手影院亚洲欧美| 激情丁香综合| 成人两性免费视频| 黄色小视频在线免费观看| 亚洲综合偷拍欧美一区色| 激情 小说 亚洲 图片: 伦| 成人h动漫精品一区二区器材| 视频在线观看99| av一级在线观看| 成人深夜视频在线观看| 一区二区在线观看网站| 91精品影视| 日韩精品在线观看视频| 免费一级肉体全黄毛片| 日本va欧美va精品发布| 麻豆传媒一区| aa级大片免费在线观看| 欧美一区永久视频免费观看| 国产午夜精品福利视频| 西西人体一区二区| 国产区欧美区日韩区| 99福利在线| 8x8x8国产精品| 欧美成人短视频| 天堂一区二区在线| 免费精品视频一区| 最新中文字幕在线播放| 亚洲精品一区二区精华| 久久久精品91| 国产成人自拍网| 可以在线看黄的网站| 在线不卡一区| 精品激情国产视频| 一级特黄色大片| 成人欧美一区二区三区白人 | 亚洲精品一区二区三区影院| 久久久www成人免费毛片| 国产寡妇亲子伦一区二区| 一级黄色片播放| 精品一区二区三区四区五区| 不用播放器成人网| www.日本在线观看| 亚洲午夜在线视频| 制服丝袜第一页在线观看| 亚洲激情二区| 免费国产一区二区| 在线成人视屏| 最新69国产成人精品视频免费| 进去里视频在线观看| 国产精品久久久一本精品 | 国产乱码午夜在线视频| 日韩h在线观看| 国产伦精品一区二区三区视频我| 国产亚洲一区二区在线观看| 中文久久久久久| 欧美激情黄色片| 97超级在线观看免费高清完整版电视剧| 久久五月精品| 精品久久久久久久久久久久包黑料| 精品亚洲永久免费| 久久在线观看免费| 国产免费又粗又猛又爽| 午夜久久黄色| 久久久com| 久久91视频| 欧美成人精品xxx| 天天爽夜夜爽夜夜爽| 91国产免费观看| 欧产日产国产v| av在线综合网| 亚洲成人天堂网| 亚洲午夜av| 日韩hmxxxx| 日日夜夜精品| 97精品久久久中文字幕免费| 国产三级视频在线播放线观看| 69堂国产成人免费视频| 日本一级一片免费视频| 中文字幕高清不卡| 在线观看免费视频国产| 日本伊人色综合网| 少妇一晚三次一区二区三区| 免费av一区| 亚洲xxxxx| 六月婷婷综合| 欧美巨猛xxxx猛交黑人97人| 日本大片在线观看| 日韩视频一区二区| 国产精品尤物视频| 亚洲成在人线免费| 成人一级片免费看| 91丨九色丨蝌蚪富婆spa| 欧美性受xxxxxx黑人xyx性爽| 99在线|亚洲一区二区| 在线观看欧美亚洲| 九九久久电影| 国产精品.com| 99re8精品视频在线观看| 国产98色在线| 多野结衣av一区| 欧美成人一二三| 大片免费播放在线视频| 亚洲精品福利在线观看| 精品乱子伦一区二区| 欧亚洲嫩模精品一区三区| 日本三级午夜理伦三级三| 国产精品黄色在线观看| 级毛片内射视频| 99re热这里只有精品视频| 佐山爱在线视频| 久久精品国产精品青草| 欧在线一二三四区| 99精品福利视频| 久久亚洲国产成人精品无码区| 色135综合网| 日韩国产美国| 国产一区二区三区四区五区| 久99久视频| 国产毛片久久久| 粉嫩av四季av绯色av第一区| 国产一区二区av在线| 国产欧美一区二区三区视频| 婷婷激情一区| 日本sm极度另类视频| 欧美男男tv网站在线播放| 欧美人与性动交| 羞羞的网站在线观看| 欧美成人免费播放| caoporm免费视频在线| 久久精品2019中文字幕| 久久久久久久久免费视频| xxxxx91麻豆| 黄色网页网址在线免费| 久久精品99国产精品酒店日本| 亚洲麻豆精品| 久久精品国产99国产精品澳门| 国产一级在线| 永久免费精品影视网站| 99中文字幕一区| www.美女亚洲精品| 国产1区在线| 欧美成人剧情片在线观看| 日本欧美电影在线观看| 欧美精品videos性欧美| 高潮在线视频| 庆余年2免费日韩剧观看大牛| 欧美羞羞视频| 国产精品女人网站| 伊人久久大香| 99热99热| 欧美午夜18电影| 欧美日韩综合精品| 欧美gvvideo网站| 亚洲小视频在线播放| 欧美午夜不卡| 9色porny| 久久激情久久| 日本人69视频| 成人免费视频caoporn| 精品黑人一区二区三区观看时间| 久久久精品日韩欧美| 中文天堂资源在线| 亚洲免费观看高清完整版在线观看| 久久香蕉精品视频| 欧美午夜精品久久久久久久| 黄色大全在线观看| 欧美一卡2卡3卡4卡| 蜜桃视频污在线观看| 亚洲图中文字幕| 黄色的网站在线观看| 国内精品模特av私拍在线观看| 一区二区乱码| 91亚洲国产成人久久精品网站| 国内精品国产成人国产三级粉色| 欧美精品免费观看二区| 亚洲电影在线一区二区三区| 成人网站免费观看入口| 日韩综合在线视频| 成年人看片网站| 国产欧美精品一区二区三区四区| 老熟妻内射精品一区| 五月婷婷综合在线| 亚洲天堂视频在线| 亚洲国产精品久久久久秋霞蜜臀 | 久久久久久久国产视频| 色综合天天综合网国产成人综合天| 一道本在线视频| 日韩精品免费一线在线观看| 成人影院在线观看| 日本国产高清不卡| 国产精品中文| 日韩国产一区久久| 在线观看视频日韩| 色播五月激情五月| 91女人视频在线观看| 欧美色图亚洲视频| 欧美亚洲丝袜传媒另类| 欧美一区,二区| 久久香蕉国产线看观看av| 欧美日韩美女| 国产综合18久久久久久| 久久久久久久久99精品大| 熟妇人妻va精品中文字幕 | 91嫩草在线视频| 欧美日韩xxxx| av免费观看大全| 国产麻豆成人精品| 亚洲女人久久久| 在线精品视频一区二区| 香蕉久久一区二区三区| 欧美激情第99页| 久久久久久久久成人| 一本一道久久a久久精品综合| 午夜在线视频一区二区区别| 精品人妻一区二区三区日产| 亚洲欧美日韩在线| 91亚洲视频在线观看| 中文字幕在线国产精品| 久久天堂av| 免费久久99精品国产自| 亚洲一区二区三区四区五区午夜| 中文字幕一区二区三区人妻在线视频 | 欧美激情另类| 日韩一区二区三区久久| 国产欧美日韩久久| 一级黄色在线观看| 亚洲色图av在线| 欧美精品日日操| 欧美日韩在线一区二区三区| 久久精品主播| 99精品欧美一区二区| 欧美亚洲禁片免费| www.91在线| 国产精品日韩欧美综合| 日本一区二区免费高清| 美女在线视频一区二区| 国产精品国产三级国产aⅴ中文 | 中文字幕中文字幕在线中高清免费版| 91精品国产自产在线| 国产精品黑丝在线播放| 日韩欧美理论片| 亚洲激情成人在线| 亚洲精品中文字幕成人片| 久久久欧美一区二区| 欧美日韩一区二区三区不卡视频| 黄页网站在线观看视频| 91免费看视频| 国产精品久久久久久久久夜色| 中日韩美女免费视频网站在线观看| 久久精品黄色| 白白操在线视频| 99国产麻豆精品| 久久人人爽人人爽人人片av免费| 这里只有精品在线播放| 老司机亚洲精品一区二区| 日本在线xxx| 久久久噜噜噜久久中文字幕色伊伊| 中文字幕乱码在线观看| 久久综合伊人77777| 成人在线视频中文字幕| av动漫免费看| 亚洲欧洲精品成人久久奇米网| 99久久久久成人国产免费| 久久久久这里只有精品| 国产成人影院| 亚洲欧美日韩网站| 精品久久久视频| 91成人高清| 国产精品对白一区二区三区| 免费日韩视频| 欧美第一页在线观看| 精品国产免费视频| 在线观看精品| 大陆极品少妇内射aaaaaa| xfplay精品久久| av男人天堂av| 国产mv久久久| 欧美激情无毛| 国产传媒国产传媒| 精品国产麻豆免费人成网站|