iT邦幫忙

2021 iThome 鐵人賽

DAY 9
2
Modern Web

用30天更加認識 React.js 這個好朋友系列 第 9

Day9-React Hook 篇-認識 useCallback

今天介紹的是 useCallback hook,透過它可以對一個函式重新執行的時機做出控制。

useCallback 真的是效能優化的利器?倒也不一定,看你怎麼使用它,過度使用反而只是拖垮效能罷了

useCallback

useCallback 的用法是將一個函式包覆並將該函式記憶起來,最後回傳記憶的函式。

useCallback: 記憶的是函式
useMemo: 記憶的是函式執行後的回傳值

使用原因

1. 避免子元件不必要的渲染,常記憶 useEffect 的 dependency array 內的函式,或是 props 內的函式使用

透過 useCallback 的記憶功能去避免子元件不必要的渲染,本文結尾的部分有範例實作這點。

一個常見對 useCallback 的誤解

在 React 官方文件提到 在 render 時建立 function,Hooks 會變慢嗎?,看過內容後就知道不會,因此 useCallback 不是為了解決元件內部過多內部函式導致的性能問題。

2. 彌補 React.memo 的缺點

除了可以減少不必要的渲染外,useCallback 也可以彌補 React.memo 的缺點,還記得 React.memo 是 shallow compare 嗎?

透過 useCallback 可以記住 function 的記憶體位置,就可以避免 React.memo 在比較 props 值時因為"物件型別記憶體位置不同但值相同"而重新渲染的狀況。

語法

const memoizedCallback = useCallback(
  () => {
    doSomething(a, b);
  },
  [a, b],
);
  • 第一個參數是 callback function
  • 第二個參數是一個陣列,此陣列不作為傳到 callback function 的參數
    • useCallback(callback): 如果沒有加上這個陣列,每次都會重新執行函式去產生新的函式
    • useCallback(callback, []): 空陣列的話,回傳的函式不會改變
    • useCallback(callback, [...someValues]): 有加上一些元素值的話,當元素值改變時會重新更新回傳的函式

範例

在 resetCount 函式加上 useCallback,使得 Child 元件不會重新渲染。

App.js

import React, { useState, useCallback } from "react";
import Child from "./Child";

const App = () => {
  const [count, setCount] = useState(0);
  console.log("re-render parent component");

  const resetCount = useCallback(() => {
    setCount(0);
  }, []);
  return (
    <>
      <p>Count: {count}</p>
      <button onClick={() => setCount((count) => count + 1)}>Increment</button>
      <Child reset={resetCount} />
    </>
  );
};

export default App;

Child.js

import React, { memo } from "react";

const Child = memo(({ reset }) => {
  console.log("re-render child component.");
  return (
    <>
      <p>child component which resets count</p>
      <button onClick={reset}>Reset Count</button>
    </>
  );
});

export default Child;

程式碼(codesandbox)


上一篇
Day8-React Hook 篇-認識 useMemo
下一篇
Day10-React Hook 篇-打造自己的 Hook:Custom Hook
系列文
用30天更加認識 React.js 這個好朋友33
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言