ReactJS - useCallback



useCallback hook 類似於 useMemo hook,它提供記憶函式而非值的功能。由於回撥函式是 JavaScript 程式設計中不可或缺的一部分,並且回撥函式是透過引用傳遞的,因此 React 提供了一個單獨的 hook,useCallback 來記憶回撥函式。理論上,useMemo hook 本身可以實現 useCallback 的功能。但是,useCallback 提高了 React 程式碼的可讀性。

useCallback hook 的簽名

useCallback hook 的簽名如下:

const <memoized_callback_fn> = useCallback(<callback_fn>, <dependency_array>);

這裡,useCallback 接受兩個輸入並返回一個記憶的回撥函式。輸入引數如下:

  • callback_fn - 要記憶的回撥函式。

  • dependency_array - 包含回撥函式所依賴的變數。

useCallback hook 的輸出是 callback_fn 的記憶回撥函式。useCallback hook 的使用方法如下:

const memoizedCallbackFn = useCallback(() => {
   // code
}, [a, b])

注意 - useCallback(callback_fn, dependency_array) 等效於 useMemo(() => callback_fn, dependency_array)。

應用 useCallback

讓我們學習如何透過建立一個 React 應用來應用 useCallback hook。

首先,使用 create-react-app 命令建立一個並啟動一個 React 應用,如下所示:

create-react-app myapp
cd myapp
npm start

接下來,在 components 資料夾下建立一個元件 PureListComponent (src/components/PureListComponent.js)

import React from "react";
function PureListComponent() {
   return <div>List</div>
}
export default PureListComponent

接下來,使用 PureListComponent 元件更新根元件,如下所示:

import PureListComponent from './components/PureListComponent';
function App() {
   return (
      <div style={{ padding: "5px" }}>
         <PureListComponent />
      </div>
   );
}
export default App;

接下來,開啟 PureListComponent.js 並新增兩個 props

  • 要在元件中顯示的專案列表

  • 用於在控制檯中顯示使用者點選的專案的回撥函式

import React from "react";
function PureListComponent(props) {
   const items = props['items'];
   const handleClick = props['handleClick']
   console.log("I am inside the PureListComponent")
   return (
      <div>
         {items.map((item, idx) =>
            <span key={idx} onClick={handleClick}>{item} </span>
         )}
      </div>
   )
}
export default React.memo(PureListComponent)

這裡我們有:

  • 使用 items props 獲取專案列表

  • 使用 handleClick 獲取點選事件的處理程式

  • 使用 React.memo 包裝元件以記憶元件。由於元件將為給定的輸入集渲染相同的輸出,因此它在 React 中被稱為 PureComponent。

接下來,讓我們更新 App.js 並使用 PureListComponent,如下所示:

import React, {useState, useEffect} from 'react';
import PureListComponent from './components/PureListComponent';
function App() {
   
   // array of numbers
   var listOfNumbers = [...Array(100).keys()];
   
   // callback function
   const handleCallbackFn = (e) => { console.log(e.target.innerText) }
   const [currentTime, setCurrentTime] = useState(new Date())
   useEffect(() => {
      let interval = setInterval(() => {
         setCurrentTime(new Date())
      }, 1000)
      return () => clearInterval(interval)
   }, [currentTime])
   return (
      <div style={ { padding: "5px" } }>
         <PureListComponent items={listOfNumbers} handleClick={handleCallbackFn}/>
         <div>Time: <b>{currentTime.toLocaleString().split(',')[1]}</b></div>
      </div>
   );
}
export default App;

這裡我們包含了一個狀態 currentTime,並使用 setInterval 每秒更新它,以確保元件每秒重新渲染。

我們可能認為 PureListComponent 不會每秒重新渲染,因為它使用了 React.memo。但是,它會重新渲染,因為 props 值是引用型別。

接下來,更新根元件並使用 useMemouseCallback 來保留陣列和回撥函式,如下所示:

import React, {useState, useEffect, useCallback, useMemo} from 'react';
import PureListComponent from './components/PureListComponent';
function App() {
   
   // array of numbers
   const listOfNumbers = useMemo(() => [...Array(100).keys()], []);
   
   // callback function
   const handleCallbackFn = useCallback((e) => console.log(e.target.innerText), [])
   const [currentTime, setCurrentTime] = useState(new Date())
   useEffect(() => {
      let interval = setInterval(() => {
         setCurrentTime(new Date())
      }, 1000)
      return () => clearInterval(interval)
   }, [currentTime])
   return (
      <div style={ { padding: "5px" } }>
         <PureListComponent items={listOfNumbers} handleClick={handleCallbackFn}/>
         <div>Time: <b>{currentTime.toLocaleString().split(',')[1]}</b></div>
      </div>
   );
}
export default App;

這裡我們有:

  • 使用 useMemo 保留 items 陣列

  • 使用 useCallback 保留 handleClick 回撥函式

最後,在瀏覽器中檢查應用程式,它將不會每秒重新渲染 PureListComponent。

Signature of the UseCallback Hook

useCallback 的用例

useCallback hook 的一些用例如下:

  • 具有函式 props 的純函式元件

  • useEffect 或其他具有函式作為依賴項的 hooks

  • 在去抖動/節流或類似操作期間使用函式

優點

useCallback hook 的優點如下:

  • 易於使用的 API

  • 易於理解

  • 提高應用程式的效能

缺點

從技術上講,useCallback 沒有缺點。但是,在應用程式中過度使用 useCallback 會帶來以下缺點。

  • 降低應用程式的可讀性

  • 降低應用程式的可理解性

  • 除錯應用程式很複雜

  • 開發人員應該深入瞭解 JavaScript 語言才能使用它

總結

useCallback 易於使用並提高效能。同時,useCallback 應該只在絕對必要時使用。它不應該在每種情況下都使用。一般規則是檢查應用程式的效能。如果需要改進,那麼我們可以檢查使用 useCallback 是否有助於提高效能。如果我們得到肯定的回應,那麼我們可以使用它。否則,我們可以將其留給 React 來改進和最佳化應用程式的效能。

廣告