[React.js] - パート14: React Hooks - useCallback Hook

Ace Lennox
2025年01月19日読了時間:3分

ReactのuseCallbackフックは、コールバック関数をメモ化することでパフォーマンスを向上させます。メモ化とは、値をキャッシュして再計算を不要にする仕組みのことです。このガイドでは、useCallbackの使い方を簡単な例を使ってわかりやすく解説します。


useCallbackとは?

useCallbackフックは、メモ化されたコールバック関数を返します。この関数は、依存関係が変更された場合にのみ再生成されます。特に、関数をプロパティとして渡すコンポーネントでReact.memoと組み合わせて使用することで、再レンダリングを防ぐのに役立ちます。

主なポイント

  1. 関数のメモ化: 不要な再生成を防ぎます。

  2. パフォーマンス最適化: 子コンポーネントの再レンダリングを減らします。

  3. useMemoとの違い: useMemoメモ化された値を返し、useCallbackメモ化された関数を返します。


問題:不要な再レンダリング

親コンポーネントでタスクのリストを管理するアプリを作成しましょう。

例:useCallbackなし

index.js

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

const App = () => {
  const [count, setCount] = useState(0);
  const [tasks, setTasks] = useState([]);

  const increment = () => {
    setCount((c) => c + 1);
  };

  const addTask = () => {
    setTasks((prevTasks) => [...prevTasks, `Task ${prevTasks.length + 1}`]);
  };

  return (
    <>
      <Tasks tasks={tasks} addTask={addTask} />
      <hr />
      <div>
        Count: {count}
        <button onClick={increment}>Increment Count</button>
      </div>
    </>
  );
};

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

Tasks.js

import { memo } from "react";

const Tasks = ({ tasks, addTask }) => {
  console.log("Tasks component re-rendered!");
  return (
    <div>
      <h2>Tasks</h2>
      {tasks.map((task, index) => (
        <p key={index}>{task}</p>
      ))}
      <button onClick={addTask}>Add Task</button>
    </div>
  );
};

export default memo(Tasks);

問題:Tasksが再レンダリングされる理由

React.memoを使用しても、カウントが増加するたびにTasksコンポーネントが再レンダリングされます。これは、親コンポーネントが再レンダリングされるたびにaddTask関数が再生成され、参照の等価性が崩れるためです。


解決策:useCallbackの使用

useCallbackフックを使うと、依存関係が変更されない限り関数を再生成しないようにできます。

例:useCallbackを使用

index.js

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

const App = () => {
  const [count, setCount] = useState(0);
  const [tasks, setTasks] = useState([]);

  const increment = () => {
    setCount((c) => c + 1);
  };

  const addTask = useCallback(() => {
    setTasks((prevTasks) => [...prevTasks, `Task ${prevTasks.length + 1}`]);
  }, [tasks]);

  return (
    <>
      <Tasks tasks={tasks} addTask={addTask} />
      <hr />
      <div>
        Count: {count}
        <button onClick={increment}>Increment Count</button>
      </div>
    </>
  );
};

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

Tasks.js

import { memo } from "react";

const Tasks = ({ tasks, addTask }) => {
  console.log("Tasks component re-rendered!");
  return (
    <div>
      <h2>Tasks</h2>
      {tasks.map((task, index) => (
        <p key={index}>{task}</p>
      ))}
      <button onClick={addTask}>Add Task</button>
    </div>
  );
};

export default memo(Tasks);

なぜこれで動作するのか?

  • useCallbackaddTask関数をメモ化します。

  • Tasksコンポーネントは、tasksプロパティが変更された場合のみ再レンダリングされます。


ベストプラクティス

  1. React.memoと組み合わせて使用: 子コンポーネントの再レンダリングを防ぐために、useCallbackReact.memoと一緒に使用します。

  2. 依存関係を明確に: コールバック関数内で使用されるすべての変数を依存配列に含めることを忘れないでください。

  3. 必要な場合にのみ最適化: useCallbackを多用しすぎないでください。特にパフォーマンスに影響する場面で使用しましょう。


まとめ

useCallbackフックは、Reactアプリケーションのパフォーマンスを向上させるためのシンプルで効果的なツールです。関数を必要に応じて再生成し、不要な再レンダリングを減らすことで、効率的なアプリケーションを構築できます。

この記事の例を試して、useCallbackを活用してReactアプリケーションをより効率的にしてみてください!


ソースコード

このプロジェクトの完全なソースコードはGitHubで利用可能です。


最近の投稿

Latest Posts


logo

プログラミング、ウェブ開発、モバイルアプリ作成に関する洞察的な記事とチュートリアルを探索します。ReactJS、Next.js、Android、iOS、および最新のコーディングプラクティスについて学びます。実践的な例と、アプリケーションを構築するためのヒントを学びます。すべてのレベルの開発者がスキルを向上させるための理想的な場所です。

SNS

© 2025. All rights reserved