iT邦幫忙

2022 iThome 鐵人賽

DAY 24
0
Modern Web

擊敗前端面試大作戰!系列 第 24

三人行必有我師焉 ---- useMemo vs React.memo vs useCallback 三種優化 React 的方法!

  • 分享至 

  • xImage
  •  

https://ithelp.ithome.com.tw/upload/images/20221008/20148825gsxjzpVKcJ.png

這篇是優化的最後一篇文章,要來討論優化 React 的三種方法,分別是 useMemo, React.memo 和 useCallback!

useMemo vs React.memo vs useCallback

TL;DR;

  • useMemo會回傳一個被 memoized 的值。
  • useCallback會回傳一個被 memoized 的 callback function.
  • React.Memo主要是用 shallow comparison 來 memoize 一個 component .

 

useMemo

主要是用來 memoized計算複雜、耗費效能的 function,並且回傳一個值

const calculation = useMemo(() => expensiveCalculation(count), [count]);

他長得跟 useEffect 很像,用法也很類似。只有在第二個值(在這裡是count)被改變時,整個 function 才會執行。

React.Memo

第二個 React.Memo 他是用在 memoizedReact component,如果傳進該 component 的 props 沒有改變,那該 component 就不會 re-render。
注意: React.Memo 使用的是 shallow comparison,所以如果傳進去的 props 是物件的話是沒有用的

那假如我們還是想傳 object props 進去怎麼辦呢?有兩種方法可以做到!第一種是假設傳進來的 props 是 function 的時候,可以用下面會講的 useCallback 把該 function 給包住,第二種則是用 React.memo 所提供的第二個 params 來處理,React.memo 的第二個 params 是一個 compare function,讓我們可以自行去寫比較的方法。

function MyComponent(props) {
  /* render using props */
}

function areEqual(prevProps, nextProps) {
  /*
  return true if passing nextProps to render would return
  the same result as passing prevProps to render,
  otherwise return false
  */
}

export default React.memo(MyComponent, areEqual);
//範例
const areEqual = (prevProps, nextProps) =>
  JSON.stringify(prevProps) === JSON.stringfiy(nextProps);
export default React.memo(renderedTable, areEqual);

根據dan 大神的這篇文章,他建議在使用 memo 之前,試試看先把 state 提升到上一層或是下放到下一層裡面,或是可以把不需要 rerender 的部分做位置上的調整,來解決 rerender 的問題,如果還是無法解決的話,再用 memo 去處理!

useCallback

useCallback會回傳一個 memoized 的 function,通常會被使用在有大量計算的 function 上。跟 useMemo 一樣,他也是只會在第二個值被改變時,整個 function 才會執行。不一樣的地方是 useMemo 回傳的是值,而 useCallback 回傳的是 function。

const addTodo = useCallback(() => {
  setTodos((t) => [...t, "New Todo"]);
}, [todos]);

統整一下,這三者的差別是 useMemo 會回傳 memoized 的一個值,useCallback 會回傳 memoized 的 function 然後 React.memo 會回傳 memoized 的 component!
介紹完 useMemo, React.memo 和 useCallback 之後,下面我們會繼續去討論兩個很實用且常常在面試中被提出來的問題---debounce 和 throttle。

debounce

debounce 可以用在 input searchBox 來避免每次使用者打字都更改 state,造成 re-render。

//debounce實作
function debounce(func, delay) {
  let timeout = null;
  return function (...args) {
    let context = this;
    //綁定在傳進來的func上
    clearTimeout(timeout);
    //清除掉前一個timeout

    timeout = setTimeout(function () {
      func.apply(context, args);
    }, delay);
  };
}

範例看這裡

https://webdesign.tutsplus.com/tutorials/javascript-debounce-and-throttle--cms-36783
https://blog.bitsrc.io/what-is-debounce-in-javascript-a2b8e6157a5a


throttle

throttle 可以用在畫面 scrolling 時透過 throttle 來避免一次大量 scroll event

//throttle實作
//用function寫
function throttle(func, delay) {
  let inThrottle;
  let timeout = null;
  return function (...args) {
    let context = this;
    if (!inThrottle) {
      func.apply(context, args);
      inThrottle = true;
      clearTimeout(timeout);
      timeout = setTimeout(function () {
        inThrottle = false;
      }, delay);
    }
  };
}

面試題:

  1. react 優化方法
  2. 三者的差別 useMemo, React.memo 和 useCallback?
  3. debounce 實作?
  4. throttle 實作?

https://ithelp.ithome.com.tw/articles/10222749
https://www.w3schools.com/react/react_usememo.asp


上一篇
[擊敗前端面試大作戰] client-side-rendering vs server-side-rendering
下一篇
[擊敗前端面試大作戰] 前端面試必考的四題HTTP題
系列文
擊敗前端面試大作戰!30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言