當 React 程式越來越龐大,就需要考慮效能的問題。memorize hook 是 React 提供的 api,可以避免重複 render 造成的效能問題。今天來介紹一下 memorized hook 的概念及功能,並介紹一下有哪些 hook。
memorized(記憶)hook,顧名思義就是會"記憶"的 hook,他們會將依賴參數的狀態記憶下來,並且只有依賴參數發生變化時才會執行更新。
依賴參數(dependencies):hooks 中傳入的參數,當 hook 偵測到變化,便會更新 hook。例如:useEffect 的第二個 Array 參數。
由於 React 的 functional component 容易常常更新,像是當父元件 re-render 時,下面的所有子元件也會跟著更新,但若父元件只有 state 更新,子元件是不需要更新的。為了避免一直更新導致網站的效能低落,就會需要 memorized hook。
除此之外,若是有執行時間很長的函式存在,為了避免每次 re-render 都要重新執行一次,導致等待時間拉長,也會使用 memorized hook。
舉個例子,假若說元件內有個 function 要執行 10 秒,在沒有使用 memorized hook 的情況下,每次 re-render 都要花 10 秒,更新三次就要多花 30 秒,非常花時間。
但若是使用 memorized hook ,就相當於是把之前做好的資料放在抽屜中一樣,再次渲染時只需要從抽屜拿出資料來用,花費時間 0 秒,渲染三次只需要等待函數 10 秒。
除非依賴參數發生變化,不然 hook 不會更新,可以大大縮短等待時間並提升效能。
const slowFunction = (num) => {
console.log("slow fn is running...")
for(let i = 0; i < 1000000; i++){}
return num + 1
}
const newNumber = useMemo(()=>slowFunction(num), [num])
// newNumber 是 useMemo 中第一個參數(函式)的回傳值
const slowFunction = () => {...};
const newNumber = useCallback(()=>{slowFunction(num)}, [num])
// newNumber 是 useCallback 中的第一個參數(函式)
createSelector (for Redux)
與上方的方法相同,createSelector 偵測依賴參數是否發生改變,若改變則重新計算 reducer 中的 return 值。
可以參考:計算衍生資料 - Redux
React.memo
React.memo 是一個 HOC (Higher Order Component),他的功用在於避免 component 多餘的渲染,只有當 props 或 state 變動時才會重新 render component。
使用 React.memo 需要在裡面放入 component,如果有需要可以在第二個參數放入自訂函數(非必要),以比對 component props 前後差異。
React.memo(MyComponent, areEqual)
然而,由於 React.memo 預設比對的方式是 shallow compare,只有在 primitive type 時才會使用完全比對,其他會比對 reference,因此當 object 被重新分配記憶體位置時,React.memo 就會失效,即使內容仍然相同。
由於上述原因, memo 會與 useMemo 或 useCallback 憶起使用,以避免失效。
以上就是 memorized hook 的簡單介紹,之後會再詳細介紹各個 hook 。若能妥善使用 memorized hook,想必能幫助我們的程式跑得更快、效能更好!
參考資料
useCallback - React
useMemo - React
Day7-在認識 useMemo 前,先認識 React.memo
React 性能優化那件大事,使用 memo、useCallback、useMemo