React 效能瓶頸怎麼辦?用 useMemo 加速你的組件渲染!

作者: Calpa Liu
字數:1623
出版:April 8, 2025

React 組件卡頓、重新渲染太慢?本文深入解析 useMemo 的使用方式與實戰案例,幫你解決效能瓶頸,打造流暢的 React 應用體驗。

useMemo 的基本概念與工作原理

useMemo 是 React 內建的 Hook,專門用於記憶(memoize)計算結果。它能夠緩存函數的返回值,避免在每次渲染時重複執行昂貴的計算。useMemo 接受兩個參數:一個計算函數和一個依賴項陣列。當依賴項保持不變時,React 會直接返回先前緩存的值;只有當依賴項發生變化時,計算函數才會重新執行。

const memoizedValue = useMemo(() => {
  // 進行昂貴的計算
  return computeExpensiveValue(a, b);
}, [a, b]); // 依賴項陣列

在上述代碼中,只有當 a 或 b 改變時,computeExpensiveValue 函數才會被重新調用。這種機制極大地減少了不必要的計算,提高了組件的渲染效率。

useMemo 的主要優勢

優化效能表現

useMemo 的首要優勢是能夠提升應用效能。通過避免重複執行耗時的計算,useMemo 減少了不必要的處理時間,使應用響應更加迅速。

// 未使用 useMemo 的例子
const expensiveCalculation = (num) => {
  console.log("計算中...");
  for (let i = 0; i < 1000000000; i++) {
    num += 1;
  }
  return num;
};

// 使用useMemo的優化版本
const memoizedCalculation = useMemo(() => {
  return expensiveCalculation(count);
}, [count]);

在上例中,只有當 count 變化時,昂貴的計算才會執行,大大提高了效能。

避免不必要的重新渲染

React 組件在狀態或屬性變化時會重新渲染。若渲染過程中包含昂貴的計算,可能導致用戶體驗下降。使用 useMemo 可以避免這種情況,確保只在必要時進行計算。

有效管理衍生數據

在處理從狀態或屬性派生的數據時,useMemo 能確保衍生計算只在依賴項變化時執行,優化了數據處理流程。例如,對列表進行排序或過濾時,使用 useMemo 可以避免在每次渲染時重新處理整個數據集。

提升用戶體驗

通過減少計算開銷和提高響應速度,useMemo 直接改善了用戶體驗。快速的響應和流暢的交互是良好用戶體驗的基礎,而 useMemo 在這方面發揮了重要作用。

useMemo 的實際應用場景

優化耗時計算

useMemo 最典型的應用是優化耗時的計算過程,如複雜的數學運算、大量數據的處理等。

function CalculateFactorial() {
  const [number, setNumber] = useState(1);
  const factorial = useMemo(() => factorialOf(number), [number]);

  // 組件其餘部分
}

在這個例子中,階乘計算只在 number 變化時執行,避免了不必要的重複計算。

數據過濾與排序

當需要對大型數據集進行過濾或排序時,useMemo 能有效提升效能。

function BlogPosts({ posts, searchQuery }) {
  const filteredPosts = useMemo(() => {
    return posts.filter((post) =>
      post.title.toLowerCase().includes(searchQuery.toLowerCase())
    );
  }, [posts, searchQuery]);

  // 組件渲染代碼
}

這裡,只有當 posts 或 searchQuery 變化時,過濾操作才會重新執行。

API 響應緩存

useMemo 可用於緩存 API 響應,避免在每次渲染時重複請求或處理數據。

function UserData({ query }) {
  const apiData = useMemo(() => {
    return fetchDataFromAPI(query);
  }, [query]);

  // 使用 apiData 渲染 UI
}

分頁與數據顯示

在實現分頁功能時,useMemo 可以緩存已加載的頁面數據,提高翻頁時的響應速度。

const paginatedData = useMemo(() => {
  const startIndex = (currentPage - 1) * itemsPerPage;
  const endIndex = startIndex + itemsPerPage;
  return data.slice(startIndex, endIndex);
}, [currentPage, data, itemsPerPage]);

useMemo 與 useCallback 的比較

雖然 useMemo 和 useCallback 都用於優化效能,但它們有明顯的區別:useMemo 返回一個記憶化的值,而 useCallback 返回一個記憶化的函數。

// useMemo 記憶計算結果
const memoizedValue = useMemo(() => computeValue(a, b), [a, b]);

// useCallback 記憶函數本身
const memoizedCallback = useCallback(() => {
  doSomething(a, b);
}, [a, b]);

使用正確的 hook 對應正確的場景是優化 React 應用的關鍵。

最佳實踐與注意事項

使用 useMemo 時,應注意以下幾點:

  1. 不要過度使用:只在處理耗時計算時才使用 useMemo,避免為簡單操作增加不必要的複雜性。

  2. 正確設置依賴項:確保依賴項列表包含計算函數中使用的所有反應性值(如 props、state 等)。

  3. 理解效能影響:在應用變得緩慢時,使用 React Profiler 分析效能瓶頸,有針對性地應用 useMemo。

lodash 的 memoize

在 JavaScript 中,我們也可以使用 lodash 的 memoize 函數來實現類似的記憶化功能。

import _ from "lodash";

// 使用 lodash 的 memoize 函數來優化複雜計算
const memoizedFactorial = _.memoize((n: number): number => {
  if (n <= 1) return 1;
  return n * memoizedFactorial(n - 1);
});

透過使用 memoize,我們可以避免在每次呼叫時都進行耗時的計算,進而提升應用的效能。

React 19 中的效能優化:深入淺出 memo

React 19 保留了廣受歡迎的 memo 函式,為開發者提供了強大的效能優化工具。memo 的核心功能是避免函式型組件在 props 保持不變時進行不必要的重新渲染,特別適用於那些需要頻繁更新但大部分 props 保持穩定的場景。

memo 的基本使用

在 React 19 中,memo 的基本語法保持不變:

const MemoizedComponent = memo(MyComponent);

這樣簡單的包裝就能讓 React 跳過對 MyComponent 的重新渲染,除非其 props 發生變化。

自定義比較邏輯

對於更精細的控制,開發者可以提供自定義的比較函式:

const MemoizedComponent = memo(MyComponent, (prevProps, nextProps) => {
  return prevProps.id === nextProps.id && prevProps.name === nextProps.name;
});

這個例子中,只有當 id 或 name 改變時,組件才會重新渲染。

memo 與 Server Components

React 19 的一大亮點是對 Server Components 的完整支持。memo 在這個新架構中扮演著重要角色,能夠顯著減少客戶端的渲染負擔,提升應用整體效能。

最佳實踐

  1. 純粹組件:memo 最適合用於純粹的函式組件,即渲染輸出完全由 props 決定的組件。
  2. 與 useCallback 配合:在傳遞函式作為 props 時,搭配 useCallback 使用可以進一步優化效能。
  3. 適度使用:不要過度使用 memo。對於簡單的組件或經常變化的組件,memo 可能會引入不必要的複雜性。
  4. 效能測試:使用 React DevTools Profiler 來衡量 memo 的實際效能提升。

React 19 中的 memo 不僅保留了其強大的優化能力,還在新的架構下展現出更卓越的效能。透過正確使用 memo,開發者可以顯著提升 React 應用的響應速度和整體用戶體驗。

結論

useMemo 是 React 中優化效能的強大工具,通過記憶化計算結果,避免不必要的重複計算,顯著提升應用效能。在處理耗時計算、大型數據集過濾排序、API 響應緩存等場景中,useMemo 能發揮重要作用。合理使用 useMemo,結合對 React 渲染機制的深入理解,能幫助開發者構建高效、流暢的 React 應用。

然而,開發者也需謹慎使用 useMemo。過度使用可能導致代碼複雜性增加,反而影響應用的可維護性。因此,建議在實際開發中權衡效能提升與代碼複雜度,只在確實需要的地方應用 useMemo。

最後,隨著 React 的不斷發展,效能優化策略也在不斷演進。開發者應持續關注 React 的最新動態,並根據具體應用場景選擇最適合的優化方法。useMemo 作為 React 工具箱中的重要一員,將繼續在前端效能優化中扮演關鍵角色。

感謝您閱讀我的文章。歡迎隨時分享你的想法。
關於 Calpa

Calpa 擅長使用 TypeScriptReact.jsVue.js 建立 Responsive Website。

他積極參與開源社區,曾在 2019 年的香港開源大會上擔任講者,提供工作經驗和見解。此外,他也在 GitHub 上公開分享個人博客程式碼,已獲得超過 300 顆星星和 60 個分支的支持。

他熱愛學習新技術,並樂意分享經驗。他相信,唯有不斷學習才能跟上快速演變的技術環境。