選單
×
   ❮     
HTML CSS JAVASCRIPT SQL PYTHON JAVA PHP HOW TO W3.CSS C C++ C# BOOTSTRAP REACT MYSQL JQUERY EXCEL XML DJANGO NUMPY PANDAS NODEJS R TYPESCRIPT ANGULAR GIT POSTGRESQL MONGODB ASP AI GO KOTLIN SASS VUE DSA GEN AI SCIPY AWS CYBERSECURITY DATA SCIENCE
     ❯   

React useCallback Hook


React 的 useCallback Hook 返回一個記憶化的回撥函式。

將記憶化看作是快取一個值,這樣它就不需要被重新計算了。

這使我們可以隔離資源密集型函式,使它們不會在每次渲染時自動執行。

useCallback Hook 僅在其依賴項更新時執行。

這可以提高效能。

useCallbackuseMemo Hooks 類似。主要區別在於 useMemo 返回一個記憶化的*值*,而 useCallback 返回一個記憶化的*函式*。您可以在 useMemo 章節中瞭解更多關於 useMemo 的資訊。


問題

使用 useCallback 的一個原因是防止元件在 props 未更改時重新渲染。

在此示例中,您可能認為 Todos 元件在 todos 未更改時不會重新渲染

這與 React.memo 部分的示例類似。

示例

index.js

import { useState } from "react";
import ReactDOM from "react-dom/client";
import Todos from "./Todos";

const App = () => {
  const [count, setCount] = useState(0);
  const [todos, setTodos] = useState([]);

  const increment = () => {
    setCount((c) => c + 1);
  };
  const addTodo = () => {
    setTodos((t) => [...t, "New Todo"]);
  };

  return (
    <>
      <Todos todos={todos} addTodo={addTodo} />
      <hr />
      <div>
        Count: {count}
        <button onClick={increment}>+</button>
      </div>
    </>
  );
};

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<App />);

Todos.js

import { memo } from "react";

const Todos = ({ todos, addTodo }) => {
  console.log("child render");
  return (
    <>
      <h2>My Todos</h2>
      {todos.map((todo, index) => {
        return <p key={index}>{todo}</p>;
      })}
      <button onClick={addTodo}>Add Todo</button>
    </>
  );
};

export default memo(Todos);

執行示例 »

嘗試執行此程式碼並點選計數器遞增按鈕。

您會注意到,即使 todos 未改變,Todos 元件也會重新渲染。

為什麼這不起作用?我們正在使用 memo,所以 Todos 元件不應該重新渲染,因為在遞增計數時 todos 狀態和 addTodo 函式都沒有改變。

這是因為一個叫做“引用相等性”的東西。

每次元件重新渲染時,其函式都會被重新建立。因此,addTodo 函式實際上已經改變了。


w3schools CERTIFIED . 2022

獲得認證!

完成 React 模組,完成練習,參加考試,並獲得 w3schools 認證!

$95 註冊

解決方案

為了解決這個問題,我們可以使用 useCallback hook 來防止函式在沒有必要時被重新建立。

使用 useCallback Hook 來防止 Todos 元件不必要地重新渲染

示例

index.js

import { useState, useCallback } from "react";
import ReactDOM from "react-dom/client";
import Todos from "./Todos";

const App = () => {
  const [count, setCount] = useState(0);
  const [todos, setTodos] = useState([]);

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

  return (
    <>
      <Todos todos={todos} addTodo={addTodo} />
      <hr />
      <div>
        Count: {count}
        <button onClick={increment}>+</button>
      </div>
    </>
  );
};

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<App />);

Todos.js

import { memo } from "react";

const Todos = ({ todos, addTodo }) => {
  console.log("child render");
  return (
    <>
      <h2>My Todos</h2>
      {todos.map((todo, index) => {
        return <p key={index}>{todo}</p>;
      })}
      <button onClick={addTodo}>Add Todo</button>
    </>
  );
};

export default memo(Todos);

執行示例 »

現在,Todos 元件僅在 todos prop 更改時重新渲染。


×

聯絡銷售

如果您想將 W3Schools 服務用於教育機構、團隊或企業,請傳送電子郵件給我們
sales@w3schools.com

報告錯誤

如果您想報告錯誤,或想提出建議,請傳送電子郵件給我們
help@w3schools.com

W3Schools 經過最佳化,旨在方便學習和培訓。示例可能經過簡化,以提高閱讀和學習體驗。教程、參考資料和示例會不斷審查,以避免錯誤,但我們無法保證所有內容的完全正確性。使用 W3Schools 即表示您已閱讀並接受我們的使用條款Cookie 和隱私政策

版權所有 1999-2024 Refsnes Data。保留所有權利。W3Schools 由 W3.CSS 提供支援