前言
在使用 React hooks 進行開發時,useMemo 和 useCallback 是兩個常被提及的性能優化工具。它們都屬於 記憶化(memoization) 技術,用來避免不必要的重算與重渲染。然而,很多初學者在理解這兩者的用途與差異時常感到困惑。這篇文章將從概念出發,並搭配實際範例,幫助你掌握 useMemo 與 useCallback 的核心用途與實作方式。
一、共通點:記憶化
React 在每次組件渲染時,預設會重新執行所有函式與表達式。當某些值(如計算結果、函式)在依賴未改變的情況下不需要重新產生,我們可以利用記憶化來優化效能。
這就是 useMemo 和 useCallback 的主要功能:根據依賴陣列(dependency array)決定是否重建值或函式。
二、差異概念總覽
| Hook | 主要用途 | 回傳內容 | 使用時機 |
|---|---|---|---|
useMemo |
記憶「計算結果」 | 任意值 | 計算過程昂貴,避免重複運算 |
useCallback |
記憶「函式定義」 | 函式 | 傳遞函式給子元件,避免不必要的 re-render |
換句話說:
useMemo(fn, deps)≈const value = memoized(fn)useCallback(fn, deps)≈const callback = memoized(() => fn)
三、useMemo 範例
假設我們有一個需要進行繁重計算的函式,例如統計某個資料集合中的數值:
import React, { useState, useMemo } from 'react'; |
在這個例子中,若不使用 useMemo,只要任何 state 改變(例如點擊按鈕改變 count),整個組件都會重新執行 slowFunction,導致效能問題。透過 useMemo,只有 input 改變時才會重新計算,其他情況會重複使用上次的計算結果。
四、useCallback 範例
有時候我們會將函式作為 props 傳遞給子元件。如果每次重新 render 都產生新的函式實例,會導致子元件誤以為 props 改變,而重新渲染。這時就可以用 useCallback。
import React, { useState, useCallback, memo } from 'react'; |
在這個範例中,ChildButton 是經過 memo 包裹的元件,只有在 props.onClick 改變時才會重新渲染。使用 useCallback 確保 handleClick 函式在 [](無依賴)下只會創建一次,即使 other 改變,ChildButton 也不會重新渲染。
五、常見錯誤與注意事項
過度使用會反效果
useMemo和useCallback本身也有記憶成本,不建議過度使用。只有在你確定函式或運算昂貴,或造成子元件重 render 才需要用。依賴陣列要正確
記得將函式中引用的變數正確加入依賴陣列中,否則會造成記憶結果與預期不符。搭配
React.memo效果更明顯useCallback通常與memo或PureComponent搭配,否則即使函式地址一樣,也無法避免重 render。
六、總結
當你在開發中遇到效能瓶頸或元件不必要地重複渲染時,才是使用 useMemo 與 useCallback 的好時機。舉例來說:
- 在表格過濾、排序等涉及大量資料處理的畫面中,可以用
useMemo優化計算。 - 在表單中將函式傳遞給
input元件時,使用useCallback可避免整個表單重 render。
記住一個原則:不要為了使用 hook 而使用,而是根據實際效能需求進行優化。如果你的應用很小或尚未遇到效能問題,先專注於撰寫可讀性高、邏輯清楚的程式碼,這才是最重要的。