精品欧美一区二区三区在线观看 _久久久久国色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技術棧公眾號

欧美精品第一页| 久久精品一区二区三区四区| 久久91亚洲精品中文字幕奶水| 亚洲 自拍 另类 欧美 丝袜| 精精国产xxxx视频在线播放| 国产偷国产偷精品高清尤物| 147欧美人体大胆444| 久久精品国产成人av| 国产精品不卡| 亚洲女人天堂视频| www.久久com| 韩日精品一区二区| 一区二区三区成人| 亚洲电影一二三区| 欧美亚洲精品在线观看| 美女精品自拍一二三四| 亚州国产精品久久久| 91成人精品一区二区| 久久99精品久久久久久欧洲站| 欧美色综合网站| 国产婷婷一区二区三区| 米奇777四色精品人人爽| 成人国产亚洲欧美成人综合网| 国产精品视频成人| 亚洲久久在线观看| 欧美午夜影院| 免费97视频在线精品国自产拍| 国产精品扒开腿做爽爽| 久久aimee| 日韩精品在线一区| 成人不卡免费视频| 欧美日韩国产网站| 色女孩综合影院| 日本少妇高潮喷水视频| 欧美大片黄色| 一区二区三区欧美在线观看| 一区二区三区免费看| 国产高清免费av在线| 久久综合久久99| 成人av男人的天堂| 国产黄色高清视频| 国产一区二区h| 91久久精品美女高潮| 一级特黄aa大片| 蜜臀国产一区二区三区在线播放 | 四虎精品免费视频| 久久中文字幕av一区二区不卡| 亚洲男人天堂古典| 六月婷婷七月丁香| 国产精品密蕾丝视频下载| 日韩精品视频免费| 亚洲成人av免费在线观看| 欧美freesex8一10精品| 亚洲国产精品高清久久久| 色哟哟视频在线| 粉嫩一区二区三区四区公司1| 欧美日韩高清一区| 色综合五月婷婷| 精品三级久久久| 日韩欧美国产小视频| 欧洲熟妇的性久久久久久| www.国产精品一区| 亚洲国产一区二区三区在线观看 | 你微笑时很美电视剧整集高清不卡| 亚洲国产日韩精品在线| 免费在线观看成年人视频| 亚洲电影一级片| 国产亚洲精品美女久久久| 黄色免费一级视频| 亚洲欧洲日韩| 国模精品视频一区二区| 日本中文字幕久久| 日本vs亚洲vs韩国一区三区二区| 国产日本欧美在线观看| a在线观看免费| k8久久久一区二区三区| 日本最新一区二区三区视频观看| 久草视频视频在线播放| 中文字幕在线不卡| 亚洲熟妇无码一区二区三区| 日韩电影大全网站| 91精品久久久久久久91蜜桃| 白嫩情侣偷拍呻吟刺激| 欧洲视频一区| 日韩在线精品视频| 日韩成人高清视频| 秋霞国产午夜精品免费视频| 91传媒视频在线观看| 亚洲日本在线播放| 中文字幕一区二| 国产精品久久..4399| 成人在线免费av| 精品久久久久久综合日本欧美| 午夜理伦三级做爰电影| 亚洲情侣在线| 清纯唯美日韩制服另类| 99热这里只有精品5| 91免费观看视频在线| 国产精品av免费| 天堂中文最新版在线中文| 91麻豆精品国产91久久久使用方法 | 精品一区二区日韩| 久久精品国产一区二区三区日韩| 日韩理伦片在线| 欧美日韩激情小视频| www.51色.com| 亚洲精品国模| 久久久久久久国产| 一级黄色大片免费| 久久综合久久久久88| 久久久久久久9| 国产成人免费视频网站视频社区 | 欧美色精品在线视频| 亚洲 欧美 日韩在线| 91av精品| 国产精品色悠悠| 青青草视频免费在线观看| 一区二区成人在线观看| 岛国av在线免费| 精品香蕉视频| 欧美制服第一页| 欧美熟妇另类久久久久久不卡 | 在线中文字幕日韩| 亚洲视频 欧美视频| av在线不卡电影| 欧美黑人在线观看| 日韩精品一区二区三区中文在线| 在线看福利67194| 无码人妻精品一区二区50| av成人免费在线观看| 国产一级大片免费看| 高清不卡一区| 日韩一区二区av| 亚洲一级av毛片| 国产欧美日韩三区| 日韩视频在线免费看| 欧美人妖在线观看| 97免费中文视频在线观看| 韩国av免费在线| 亚洲综合久久久| 韩国一区二区三区四区| 欧美a级片一区| 97人人香蕉| 成人影音在线| 亚洲国产欧美一区| 五月天综合激情网| 久久男人中文字幕资源站| 欧美极品欧美精品欧美图片| 国产精品一区二区三区美女| 97视频免费在线观看| 天堂在线视频网站| 黑人巨大精品欧美一区免费视频 | 伊人五月天婷婷| 欧美在线不卡| 成人9ⅰ免费影视网站| 国产精品国精产品一二| 亚洲国产精品人久久电影| 日韩黄色a级片| 久久婷婷久久一区二区三区| 国产97色在线 | 日韩| 青青一区二区三区| 91精品视频免费| 日本天码aⅴ片在线电影网站| 精品国产乱码久久久久久闺蜜| 国产大片aaa| 91视频一区二区| av网站在线不卡| 亚洲欧美综合久久久| 精品国产电影| 日本一道高清亚洲日美韩| www.亚洲一区| 亚洲乱码在线观看| 色综合色狠狠天天综合色| 久久久久久久毛片| 国产麻豆视频一区二区| 免费看国产曰批40分钟| 精品国产乱码| 亚洲最大成人在线| 看黄在线观看| 色爱精品视频一区| 欧美 日韩 国产 成人 在线| 色综合久久久久综合| 女性裸体视频网站| 不卡视频在线观看| 久久综合伊人77777麻豆最新章节| 91成人影院| 久久亚洲精品欧美| www久久久| 2019中文字幕在线| 国产精品久久久久久福利| 日韩精品一区二区三区视频在线观看 | 亚洲成人动漫在线观看| 久操视频在线观看免费| 国产ts人妖一区二区| 无码人妻丰满熟妇区毛片18| 91精品1区| 视频一区国产精品| 国产精品白浆| 91精品视频大全| 国产精品久久久久av电视剧| 欧美高清在线播放| av在线第一页| 日韩电影视频免费| 国产后入清纯学生妹| 在线精品亚洲一区二区不卡| 国产精品.www| 日韩美女啊v在线免费观看| 中文字幕5566| 成人av免费在线观看| xxxx在线免费观看| 久久久久欧美精品| 97超碰人人澡| 欧美日韩亚洲三区| 中文字幕免费在线不卡| 自拍自偷一区二区三区| 国产欧美日韩一区二区三区| 欧洲亚洲精品| 国产精品久久久久久亚洲影视 | 日本韩国欧美一区二区三区| 国产 日韩 欧美 成人| 亚洲日本中文字幕区| 四季av中文字幕| 久久综合狠狠综合久久激情| 国产伦精品一区二区三区精品| 国产一区二区三区在线观看精品 | 91麻豆国产自产在线观看| 久久黄色一级视频| 国产一区二区在线影院| 岛国av在线免费| 久久精品久久精品| 97公开免费视频| 爽好多水快深点欧美视频| 国产综合av在线| 中文高清一区| 成人黄色av片| 一本色道久久综合亚洲精品不| 污污污污污污www网站免费| 亚洲经典一区| 国产精品12p| 中文不卡在线| 欧美 亚洲 视频| 韩日成人在线| 国产真人做爰毛片视频直播| 亚洲欧洲日本mm| 毛片在线播放视频| 一区二区高清| 成人小视频在线看| 日韩精品视频网站| 久久久久国产一区| 精品在线免费观看| 久久久久久久久久毛片| 国产伦精品一区二区三区视频青涩| 天天做天天干天天操| 国产一区二区精品久久91| 欧美xxxx日本和非洲| 成人午夜免费视频| 青青草视频播放| 国产调教视频一区| 女人裸体性做爰全过| 亚洲人妖av一区二区| 国产大片中文字幕| 欧美午夜视频在线观看| 中文人妻熟女乱又乱精品| 欧美日韩一区高清| av中文字幕观看| 亚洲国产日韩欧美在线99| 国产在线一二三区| www.国产精品一二区| 性xxxfreexxxx性欧美| 97热精品视频官网| 97欧美成人| 2020国产精品久久精品不卡| 久本草在线中文字幕亚洲| 欧美成ee人免费视频| 日韩精品dvd| av片在线免费| 日韩中文字幕不卡| 午夜影院免费观看视频| 不卡av电影在线播放| 高清国产在线观看| 亚洲老妇xxxxxx| 无码人妻丰满熟妇区bbbbxxxx| 欧美日韩1234| 亚洲aaa在线观看| 最新91在线视频| 国产剧情av在线播放| 国产精品爽爽爽爽爽爽在线观看| 99re91这里只有精品| 热re99久久精品国99热蜜月| 影视亚洲一区二区三区| 日本精品免费在线观看| 韩国成人福利片在线播放| 亚洲啪av永久无码精品放毛片| 亚洲国产高清aⅴ视频| 国产在线一区视频| 欧美视频在线观看一区二区| 粉嫩小泬无遮挡久久久久久| 中文字幕不卡在线视频极品| sm在线观看| 亚洲综合在线播放| 国产一区二区三区网| cao在线观看| 久久99九九99精品| 在线不卡av电影| 一级做a爱片久久| 亚洲专区在线播放| 国产偷国产偷亚洲清高网站| 色yeye免费人成网站在线观看| 国产精品久久久精品| 欧美挤奶吃奶水xxxxx| 香蕉视频免费版| 麻豆一区二区三| 中日韩精品一区二区三区| 亚洲精品国产一区二区精华液 | 日韩精品极品在线观看播放免费视频| 免费网站看v片在线a| 国产高清在线不卡| 三级精品视频| www.av片| 成人高清视频免费观看| 午夜国产福利一区二区| 欧美在线三级电影| 黄色国产在线| 欧美亚洲国产日韩2020| 国产毛片久久久| www.成年人视频| 国产福利不卡视频| 久久国产美女视频| 欧美区在线观看| 亚洲成人影院麻豆| 国产精品久久久久久久午夜| 蜜桃tv一区二区三区| 男女激情无遮挡| av高清不卡在线| 日本熟妇毛茸茸丰满| 亚洲精品一区在线观看| 美女日批视频在线观看| 国产66精品久久久久999小说| 欧美99在线视频观看| 少妇极品熟妇人妻无码| 亚洲黄网站在线观看| 精品人妻aV中文字幕乱码色欲| 久久精品国产亚洲7777| 96sao精品免费视频观看| 国产91av视频在线观看| 久久99国产精品免费| 色欲一区二区三区精品a片| 91精品国模一区二区三区| 免费av网站在线观看| 亚洲aⅴ男人的天堂在线观看| 伊人色**天天综合婷婷| 亚洲图片欧美另类| 欧美日韩色婷婷| 蜜桃视频在线入口www| 国产97在线|日韩| 日韩理论在线| 亚洲视频在线不卡| 午夜视频在线观看一区二区三区| 视频一区 中文字幕| 国产成人精品综合久久久| 成人在线免费观看视频| 91丨九色丨蝌蚪| 亚洲制服丝袜av| 少妇性bbb搡bbb爽爽爽欧美| 国产成人一区二区三区小说| 国产精品传媒精东影业在线 | 一级久久久久久久| 欧美成人高清视频| 欧美亚洲国产日韩| 色一情一乱一伦一区二区三区日本| 国产精品成人网| 亚洲精品97久久中文字幕| 欧美亚洲国产视频小说| 国产精品二区不卡| 这里只有精品在线观看视频| 在线亚洲免费视频| 在线免费观看a视频| 久久国产精品99久久久久久丝袜| 肉肉av福利一精品导航| 我要看黄色一级片| 日韩av一区在线| 另类一区二区| 无码专区aaaaaa免费视频| 欧美国产日韩一二三区| 国产激情久久久久久熟女老人av| 91国产一区在线| 国产精品传媒精东影业在线| 精品中文字幕在线播放| 欧美日韩国产另类不卡| 黄在线观看免费网站ktv| 亚洲欧美日产图| 播五月开心婷婷综合| 在线观看中文字幕2021| 91精品国产99| 天天综合网网欲色| 蜜桃传媒一区二区亚洲av| 日韩午夜激情免费电影| 欧美日韩在线精品一区二区三区激情综合 | 亚洲成人自拍视频| 波多野结衣精品在线|