最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

React性能優(yōu)化三劍客之useMemo、memo與useCallback詳解

 更新時間:2026年04月09日 10:38:23   作者:晴梔ay  
useMemo和useCallback是React 中用于性能優(yōu)化的兩個重要 Hook,它們基于相同的依賴項比較機制,但適用場景不同,這篇文章主要介紹了React性能優(yōu)化三劍客之useMemo、memo與useCallback的相關(guān)資料,需要的朋友可以參考下

"在React世界里,每一次不必要的渲染都是對用戶體驗的無聲謀殺。" - 某位不愿透露姓名的性能優(yōu)化工程師

前言:性能優(yōu)化的必然性

當你第一次接觸React時,可能被它的聲明式編程和組件化思想所吸引。但隨著應(yīng)用復(fù)雜度增長,你是否曾經(jīng)歷過這樣的場景:一個簡單的狀態(tài)更新導(dǎo)致了整個頁面"顫動",或者滾動列表時出現(xiàn)明顯卡頓?這些現(xiàn)象背后,往往隱藏著不必要的重復(fù)渲染和昂貴計算。

今天,我們將一起探索React性能優(yōu)化的三大利器:useMemo、memouseCallback。它們就像是React世界的"防抖開關(guān)",幫我們精確控制什么該渲染,什么該緩存。

一、useMemo

1.1 問題場景:看不見的性能殺手

想象一個包含搜索功能的商品列表組件。當用戶在搜索框中輸入關(guān)鍵詞時,我們過濾商品列表。同時,頁面上還有其他無關(guān)的狀態(tài)(比如一個計數(shù)器)。代碼可能如下:

function App() {
  const [count, setCount] = useState(0);
  const [keyword, setKeyword] = useState('');
  const list = ['apple', 'banana', 'orange', 'pear'];
  // 問題就在這里!
  const filterList = list.filter(item => {
    console.log('filter 執(zhí)行');
    return item.includes(keyword);
  });
  return (
    <div>
      {count}
      <button onClick={() => setCount(count + 1)}>count + 1</button>
      <input 
        type="text" 
        value={keyword} 
        onChange={e => setKeyword(e.target.value)} 
      />
      {filterList.map(item => (
        <li key={item}>{item}</li>
      ))}
    </div>
  )
}

當你點擊"count + 1"按鈕時,控制臺會顯示"filter 執(zhí)行",盡管搜索關(guān)鍵詞根本沒有變化!這意味著每次任何狀態(tài)更新,這個過濾操作都會重新執(zhí)行。

對于簡單列表這可能影響不大,但如果過濾操作需要遍歷數(shù)千條數(shù)據(jù),或者執(zhí)行復(fù)雜計算,性能問題就會凸顯。

1.2 useMemo

useMemo就像一個智能緩存器,只在依賴項變化時重新計算:

const filterList = useMemo(() => {
  console.log('filter 執(zhí)行');
  return list.filter(item => item.includes(keyword));
}, [keyword]); // 僅當keyword變化時重新計算

現(xiàn)在,當你更新count時,過濾操作不會重新執(zhí)行,只有keyword變化時才會重新計算。這顯著減少了不必要的計算開銷。

1.3 優(yōu)化昂貴計算:真實世界的例子

考慮一個需要計算大量數(shù)據(jù)的場景:

function slowSum(n) {
  console.log('計算中...');
  let sum = 0;
  for(let i = 0; i <= n*10000000; i++) {
    sum += i;
  }
  return sum;
}
function App() {
  const [num, setNum] = useState(0);
  // 優(yōu)化前:每次組件渲染都會執(zhí)行slowSum
  const result = slowSum(num);
  // 優(yōu)化后:只在num變化時重新計算
  const result = useMemo(() => {
    return slowSum(num);
  }, [num]);
  return (
    <div>
      <button onClick={() => setNum(num + 1)}>num + 1</button>
      <p>num: {result}</p>
    </div>
  )
}

點擊按鈕時,你只會看到一次"計算中..."的日志,而不是每次渲染都計算。對于真正的計算密集型任務(wù),這種優(yōu)化可能是應(yīng)用流暢與否的關(guān)鍵。

二、React.memo

2.1 組件重渲染的連鎖反應(yīng)

React中,當父組件狀態(tài)更新時,所有子組件默認都會重新渲染,無論它們的props是否變化。這就像一棟公寓樓中,一戶人家換了燈泡,整棟樓的住戶都被通知要出來看一眼。

function Child({ count }) {
  console.log('child 重新渲染');
  return <div>子組件 count: {count}</div>
}
function App() {
  const [count, setCount] = useState(0);
  const [num, setNum] = useState(0);
  return (
    <div>
      {count}
      <button onClick={() => setCount(count + 1)}>count + 1</button>
      {num}
      <button onClick={() => setNum(num + 1)}>num + 1</button>
      <Child count={count} />
    </div>
  )
}

當你點擊"num + 1"按鈕時,Child組件也會重新渲染,盡管它的props(count)沒有變化!

2.2 memo

React.memo是一個高階組件,它對函數(shù)組件進行包裝,使其僅在props變化時重新渲染:

const Child = memo(({ count }) => {
  console.log('child 重新渲染');
  return <div>子組件 count: {count}</div>
})

現(xiàn)在,點擊"num + 1"按鈕時,Child組件不會重新渲染,因為它的props沒有變化。這就像給子組件裝上了智能門鎖,只有"真正需要進門的人"才能觸發(fā)重新渲染。

三、useCallback:函數(shù)傳遞的優(yōu)化藝術(shù)

3.1 隱藏的陷阱:函數(shù)引用變化

當父組件向子組件傳遞回調(diào)函數(shù)時,會遇到一個隱蔽問題:

const Child = memo(({ count, handleClick }) => {
  console.log('child 重新渲染');
  return <div onClick={handleClick}>子組件 count: {count}</div>
})
function App() {
  const [count, setCount] = useState(0);
  // 每次組件渲染都會創(chuàng)建新函數(shù)
  const handleClick = () => {
    console.log('click');
  }
  return (
    <div>
      {count}
      <button onClick={() => setCount(count + 1)}>count + 1</button>
      <Child count={count} handleClick={handleClick} />
    </div>
  )
}

即使使用了memo,Child組件仍然會在count變化時重新渲染!為什么?因為每次父組件渲染時,handleClick都會創(chuàng)建一個新函數(shù),導(dǎo)致子組件的props發(fā)生變化。

3.2 useCallback:函數(shù)的穩(wěn)定引用

useCallback解決了這個問題,它返回一個記憶化的回調(diào)函數(shù):

const handleClick = useCallback(() => {
  console.log('click');
}, []); // 依賴數(shù)組為空,函數(shù)永遠不會重新創(chuàng)建

如果回調(diào)需要依賴組件內(nèi)的狀態(tài)或prop,可以將它們添加到依賴數(shù)組中:

const handleClick = useCallback(() => {
  console.log('click', count);
}, [count]); // 僅當count變化時重新創(chuàng)建函數(shù)

現(xiàn)在,當count以外的狀態(tài)變化時,handleClick函數(shù)引用保持不變,Child組件不會不必要地重新渲染。

四、三大利器的協(xié)同作戰(zhàn)

在復(fù)雜應(yīng)用中,這三個優(yōu)化鉤子常常需要協(xié)同工作:

const ParentComponent = () => {
  const [searchTerm, setSearchTerm] = useState('');
  const [userList, setUserList] = useState([]);
  const [theme, setTheme] = useState('light');
  // 優(yōu)化1: 使用useMemo緩存過濾結(jié)果
  const filteredUsers = useMemo(() => {
    return userList.filter(user => 
      user.name.toLowerCase().includes(searchTerm.toLowerCase())
    );
  }, [userList, searchTerm]);
  // 優(yōu)化2: 使用useCallback確保函數(shù)引用穩(wěn)定性
  const handleUserClick = useCallback((userId) => {
    // 處理用戶點擊
  }, []);
  // 優(yōu)化3: 使用memo防止不必要的子組件渲染
  const UserList = memo(({ users, onUserClick }) => {
    return (
      <div>
        {users.map(user => (
          <UserItem 
            key={user.id} 
            user={user} 
            onClick={() => onUserClick(user.id)} 
          />
        ))}
      </div>
    );
  });
  return (
    <div>
      <SearchBar value={searchTerm} onChange={setSearchTerm} />
      <ThemeToggle theme={theme} onToggle={setTheme} />
      <UserList users={filteredUsers} onUserClick={handleUserClick} />
    </div>
  );
};

在這個例子中:

  • 當theme變化時,不會重新計算filteredUsers
  • UserList組件只在filteredUsers變化時重新渲染
  • handleUserClick保持穩(wěn)定的引用,不會導(dǎo)致UserItem不必要的重渲染

五、最佳實踐與注意事項

5.1 何時使用,何時放棄?

  • 不要過早優(yōu)化:先編寫清晰的代碼,再通過性能分析工具(如React DevTools的Profiler)識別真正的瓶頸
  • 小型計算不必緩存:如果計算非常輕量,useMemo可能帶來額外開銷
  • 避免依賴數(shù)組過大:過度依賴會導(dǎo)致緩存失效頻繁,失去優(yōu)化意義

5.2 常見誤區(qū)

  1. "所有函數(shù)都應(yīng)該用useCallback包裝"  - 錯誤!只有傳遞給優(yōu)化過的子組件(使用memo)的函數(shù)才需要
  2. "useMemo可以替代useEffect"  - 錯誤!useMemo用于計算和返回值,useEffect用于副作用
  3. "依賴數(shù)組為空總是最好的"  - 危險!可能導(dǎo)致閉包中使用過期的值

5.3 高級技巧

  • 自定義比較函數(shù):React.memo可以接受第二個參數(shù),自定義props比較邏輯
  • useRef替代方案:對于某些場景,useRef可以作為useCallback的替代方案
  • 結(jié)構(gòu)化克隆:處理復(fù)雜對象時,確保依賴項真正反映數(shù)據(jù)變化

六、性能優(yōu)化的哲學(xué)思考

在追求性能的道路上,我們常常陷入一個誤區(qū):過度優(yōu)化。就像一位廚師不斷調(diào)整食譜的細微之處,卻忘了最重要的是一道菜的整體味道。

React的性能優(yōu)化應(yīng)當遵循這樣的原則:

  • 可讀性優(yōu)先:代碼首先是給人讀的,其次才是給機器執(zhí)行的
  • 問題驅(qū)動:只在真正遇到性能問題時才進行優(yōu)化
  • 平衡之道:在性能和開發(fā)體驗之間找到平衡點

記住,最優(yōu)雅的優(yōu)化是"無需優(yōu)化"。通過良好架構(gòu)和合理狀態(tài)管理,很多性能問題在設(shè)計階段就可避免。

結(jié)語

useMemo、memo和useCallback是React性能優(yōu)化工具箱中的三件利器。它們不是解決所有問題的銀彈,而是在特定場景下精準發(fā)力的手術(shù)刀。

掌握它們的關(guān)鍵在于理解React的渲染機制,識別真正的性能瓶頸,并在恰當?shù)臅r機應(yīng)用這些技術(shù)。如React核心團隊成員Dan Abramov所言:"優(yōu)化應(yīng)該像調(diào)味品——適量使用可以提升體驗,過量則會毀掉整道菜。"

下次當你面對卡頓的UI或緩慢的交互時,不妨回想這三大利器。它們可能不會讓你的應(yīng)用瞬間飛起來,但一定會讓用戶體驗更加絲滑,就像一位隱形的管家,默默確保一切井然有序。

到此這篇關(guān)于React性能優(yōu)化三劍客之useMemo、memo與useCallback的文章就介紹到這了,更多相關(guān)React useMemo、memo與useCallback內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 解析React?ref?命令代替父子組件的數(shù)據(jù)傳遞問題

    解析React?ref?命令代替父子組件的數(shù)據(jù)傳遞問題

    這篇文章主要介紹了React?-?ref?命令為什么代替父子組件的數(shù)據(jù)傳遞,使用?ref?之后,我們不需要再進行頻繁的父子傳遞了,子組件也可以有自己的私有狀態(tài)并且不會影響信息的正常需求,這是為什么呢?因為我們使用了?ref?命令的話,ref是可以進行狀態(tài)的傳輸
    2022-08-08
  • React路由攔截模式及withRouter示例詳解

    React路由攔截模式及withRouter示例詳解

    這篇文章主要為大家介紹了React路由攔截模式及withRouter示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-08-08
  • 比ant更豐富Modal組件功能實現(xiàn)示例詳解

    比ant更豐富Modal組件功能實現(xiàn)示例詳解

    這篇文章主要為大家介紹了比ant更豐富Modal組件功能實現(xiàn)示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-11-11
  • react國際化react-intl的使用

    react國際化react-intl的使用

    這篇文章主要介紹了react國際化react-intl的使用,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習或者工作具有一定的參考學(xué)習價值,需要的朋友們下面隨著小編來一起學(xué)習學(xué)習吧
    2021-05-05
  • react的hooks防抖和節(jié)流的具體實現(xiàn)

    react的hooks防抖和節(jié)流的具體實現(xiàn)

    本文主要介紹了react的hooks防抖和節(jié)流的具體實現(xiàn),解釋了為何需要特別處理閉包問題,并提供了具體實現(xiàn)方案,文章還強調(diào)了使用useRef保存最新函數(shù)的重要性,以及兩種防抖節(jié)流方法的區(qū)別與應(yīng)用場景,感興趣的可以了解一下
    2026-05-05
  • React中的refs的使用教程

    React中的refs的使用教程

    本篇文章主要介紹了React中的refs的使用教程,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-02-02
  • React ts模式使用http-proxy-middleware代理時訪問報404問題

    React ts模式使用http-proxy-middleware代理時訪問報404問題

    這篇文章主要介紹了React ts模式使用http-proxy-middleware代理時訪問報404問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-07-07
  • 深入理解React與閉包的關(guān)系

    深入理解React與閉包的關(guān)系

    本文將深入探討React與閉包之間的關(guān)系,我們將首先介紹React和閉包的基本概念,然后詳細解釋React組件中如何使用閉包來處理狀態(tài)和作用域的問題,希望通過本文的閱讀,你將對React中閉包的概念有更深入的理解,并能夠在開發(fā)React應(yīng)用時更好地應(yīng)用閉包
    2023-07-07
  • React組件內(nèi)事件傳參實現(xiàn)tab切換的示例代碼

    React組件內(nèi)事件傳參實現(xiàn)tab切換的示例代碼

    本篇文章主要介紹了React組件內(nèi)事件傳參實現(xiàn)tab切換的示例代碼,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-07-07
  • react vite使用import.meta.glob批量導(dǎo)入路由方式

    react vite使用import.meta.glob批量導(dǎo)入路由方式

    文章介紹了如何通過動態(tài)引入模塊中的路由信息,簡化了傳統(tǒng)的路由管理方式,無需單獨引入每個模塊的路由
    2025-10-10

最新評論

阿克| 平邑县| 淮南市| 双辽市| 嫩江县| 额尔古纳市| 江城| 志丹县| 福安市| 饶阳县| 上犹县| 习水县| 晋城| 普陀区| 横峰县| 高碑店市| 鹤庆县| 宝鸡市| 邛崃市| 清流县| 灵宝市| 丰城市| 乐清市| 磐石市| 都兰县| 望谟县| 桐庐县| 扬州市| 江源县| 志丹县| 珠海市| 颍上县| 马公市| 张掖市| 五指山市| 九江市| 科尔| 伊川县| 忻州市| 台江县| 霸州市|