iT邦幫忙

2022 iThome 鐵人賽

DAY 6
0
Modern Web

React 新手村 - 填坑記系列 第 6

React 新手村 - 填坑記 - Day6 開發問題(二)

  • 分享至 

  • xImage
  •  

React hooks useMemo 與 useCallback 運用

useMemo

簡述:

Returns a memoized value. 也就是 dependencies 沒有改變的情況下,
把某個運算的值保存下來 ( 這個 slowFunction 回傳值可以是 object、array、basic type),
主要目的用來「避免重複進行複雜耗時的計算」,因此為了避免在每一次 re-render 都重新運算,
可以用 useMemo 來記住這個函式的運算結果,並在下一次 re-render 階段,
透過判斷 dependency array 是否有變化來判斷是否重新運算函式,
如果 dependency array 不變就回傳上一次的運算結果。

使用方式:

//第一個參數傳入要記住的運算函式,第二個參數傳入 dependency array。
const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b])

useCallBack

簡述:

Returns a memoized callback. 也就是 dependencies 沒有改變的情況下,
把某個 function 保存下來,主要目的是避免在 component 內部宣告的 function
因為每一次 re-render 時 function 都會分配到一個新的記憶體位址,useCallback
可以記憶住該 function 的記憶體位置,避免每一次子元件 re-render 時,
都因為 function 的記憶體位置改變導致子元件重新渲染。

使用方式:

//將要記住記憶體位置的 function 用 useCallback 包住並傳入 dependency array 當作第二個參數。
const memoizedCallback = useCallback(
  () => {
    doSomething(a, b);
  },
  [a, b],
);

如何區分useMemo & useCallBack

const tags = useMemo(() => {
        return ['happy', 'sad', 'madness'];
}, []);
console.log('This is what useMemo looks like: ', tags);

const contentHandler = useCallback(() => {
     return `I did ${count} times in my current job.`;
}, [count]);
console.log('This is what useCallback looks like: ', contentHandler);

區分兩者最大的不同在於

  • useMemo回傳的是variable
  • useCallback回傳的是function

輸出之後會變成

  • This is useMemo what looks like: (3) [“happy”, “sad”, “madness”]
  • This is useCallback what looks like: () => I did ${count} times in my current job.

使用時機推估

本身運用useMemo & useCallBack主軸都是為了效能優化,但優化的同時總是會帶來額外的成本消耗,所以運用的同時可能就需要評估一下是否合適。

  • useMemo建議使用於較複雜繁重的運算(如下),如果只是使用在簡易的計算上反而沒有使用的必要
// Assume this returns an Array of 3000 records
const menuItemRows = useMemo(
    () => thousandsOfMenuItems.map(menuItem => (
        <MenuItemRow key={menuItem.uuid} name={menuItem.name} />
    )),
    [thousandsOfMenuItems]
);
  • useCallBack當function因需要用到 props 或 state 而必須在 component scope 裡面宣告、但又同時會被超過一個 useEffect 使用時,就建議以 useCallback 包起來。不然大部分情況下,都不需要用到 useCallback
// When your callback are used in multiple useEffect() 
function SearchResults({ query }) {
    const getFetchUrl = useCallback(() => {
    return 'https://hn.algolia.com/api/v1/search?query=' + query;
    }, [query]);
useEffect(() => {
    const url = getFetchUrl('react');
    // ... Fetch data and do something ...
    }, [getFetchUrl]);
useEffect(() => {
    const url = getFetchUrl('redux');
    // ... Fetch data and do something ...
    }, [getFetchUrl]);
// ...
}

結論

useMemo & useCallBack大量使用也可能造成額外的效能問題,因此建議的使用情境如下:

  • 執行速度很慢 (Expensive function or expensive calculation)
  • 不需要常常再被 render over and over again,變動性不大

上一篇
React 新手村 - 填坑記 - Day5 開發問題(一)
下一篇
React 新手村 - 填坑記 - Day7 開發問題(三)
系列文
React 新手村 - 填坑記30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言