React基礎|useCallbackとは?なぜ使用するか解説

useCallbackは何のために使用するのか解説

6/11/2025

useCallbackとは?

関数をメモ化するのに使用する。

親コンポーネントから子コンポーネントに関数を渡している場合、親コンポーネントがレンダリングされると、渡している関数も更新されるため、関数を受け取っている子コンポーネントもレンダリングされてしまう。

✅useCallback の主な目的

関数参照の変更によって子コンポーネントの再レンダリングが起きないようにする。

📝useCallbackを使用する場合としない場合の比較

src/
├── components/
│   └── IncrementButton.jsx
├── hooks/
│   └── useCounter.js
└── App.jsx
  • 親コンポーネント(App,js)に子コンポーネント(IncrementButton.jsx)を読み込んで、クリック時の関数をpropsで渡す。
  • 関数はカスタムフック内(useCounter.js)で作成し、親コンポーネント(App,js)に読み込む。(カスタムフックでなく、親コンポーネントに直接関数を記載しても同じ)

❌useCallback( メモ化)なし:不要な再レンダリングが発生する

📁カスタムフック|hooks/useCounter.js

import { useState } from "react";

const useCounter = () => {
  const [count, setCount] = useState(0);

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

  return { count, increment };
};

export default useCounter;

📁ボタンコンポーネント|components/IncrementButton.jsx

import React from "react";

const IncrementButton = React.memo(({ onClick }) => {
  console.log("Button rendered");
  return <button onClick={onClick}>+1</button>;
});

export default IncrementButton;

📝React.memo

📁親コンポーネント|App.jsx

import React from "react";
import useCounter from "./hooks/useCounter";
import IncrementButton from "./components/IncrementButton";

const App = () => {
  const { count, increment } = useCounter();

  return (
    <div>
      <h1>Count: {count}</h1>
      <IncrementButton onClick={increment} />
    </div>
  );
};

export default App;
  • カスタムフックから、結果を表示させるcountと関数incrementを取得
  • ボタンコンポーネントに関数をincrement渡す。

⚡️結果:ボタンをクリックするたびにボタンコンポーネントがレンダリングされる

ボタンをクリックすると、count の状態が変わる。その際に再レンダリングされる。
そしてのたびに increment 関数の参照も変わる → ボタンコンポーネントもレンダリングされ、コンソールにButton rendered が毎回表示される。

❌親コンポーネントの値だけ変わればいいのに、変化がない子コンポーネントも再レンダリングする必要はない。


✅ useCallback(メモ化)あり:不要な再レンダリングを防ぐ

📁カスタムフック|hooks/useCounter.js

import { useState, useCallback } from "react";

const useCounter = () => {
  const [count, setCount] = useState(0);

  const increment = useCallback(() => {
    setCount((prev) => prev + 1);
  }, []);

  return { count, increment };
};

export default useCounter;
  • increment関数をuseCallbackでメモ化
  • 他のコンポーネントへの変更はなし

⚡️結果:increment 関数はメモ化されていて参照が変わらない → Button rendered は初回のみ表示される

親コンポーネントの初回レンダリングで子コンポーネントもレンダリングされる。それ以降は親コンポーネントのcountの値が変わっても、関数はメモ化されているので再レンダリングされない。→子コンポーネント(ボタン)の無駄なレンダリングを防ぐことができる。