ReactuseCallbackフック


React useCallbackHookは、メモ化されたコールバック関数を返します。

メモ化は、値をキャッシュして、再計算する必要がないようにすることと考えてください。

これにより、リソースを大量に消費する関数を分離して、すべてのレンダリングで自動的に実行されないようにすることができます。

useCallbackフックは、依存関係の1つが更新されたときにのみ実行されます

これにより、パフォーマンスを向上させることができます。

フックは似ていますuseCallbackuseMemo主な違いはuseMemo、メモ化されたuseCallback返し、メモ化された関数を返すことです。useMemoの詳細については、useMemoのを参照してください。


問題

使用する理由の1つuseCallbackは、小道具が変更されていない限り、コンポーネントが再レンダリングされないようにすることです。

この例では、次の変更Todosを行わない限り、コンポーネントは再レンダリングされないと考えるかもしれません。todos

これは、React.memoセクションの例と似ています。

例:

index.js

import { useState } from "react";
import ReactDOM from "react-dom";
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>
    </>
  );
};

ReactDOM.render(<App />, document.getElementById('root'));

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コンポーネントは再レンダリングされません。todosaddTodo

これは、「参照の平等」と呼ばれるものによるものです。

コンポーネントが再レンダリングされるたびに、その関数が再作成されます。このため、addTodo実際に機能が変更されました。


w3schools CERTIFIED . 2022

認定を受けましょう!

Reactモジュールを完了し、演習を行い、試験を受けて、w3schools認定を取得してください!!

95ドル登録

解決

これを修正するには、useCallbackフックを使用して、必要な場合を除いて関数が再作成されないようにします。

useCallbackフックを使用して、Todosコンポーネントが不必要に再レンダリングされないようにします。

例:

index.js

import { useState, useCallback } from "react";
import ReactDOM from "react-dom";
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>
    </>
  );
};

ReactDOM.render(<App />, document.getElementById('root'));

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