useCallbakの基本的な使い所
react公式より引用
再レンダー間で関数定義をキャッシュできるようにする
つまり再レンダリングが走った時に新しく関数を生成するのではなく、キャッシュを行いそれを実行できるようにするという意味です。(特に何もしない場合、reactは再レンダリングされるたびコンポーネント内の関数を新規作成している。)
useCallbackを使うと関数を所謂メモ化できるということです。
自分は少し分かりにくいというか、恩恵を受けずらそうだなと感じたので以下に具体例を示していきます。
関数がキャッシュされたかどうかコンソールで確認できる例
"use client";
import React, { useCallback, useEffect, useRef, useState } from "react";
export default function page() {
const [text, setText] = useState("");
//useCallbackを使わない関数
const nonMemoFunc = () => {
console.log("非メモ化関数が実行されたぜ!");
};
//useCallbackを使ってメモ化した関数
const memoFunc = useCallback(() => {
console.log("メモ化関数が実行されたぜ!");
}, []);
//前回の関数参照を保持するためのuseRef
const prevNonMemoFunc = useRef<() => void>();
const prevMemoFunc = useRef<() => void>();
//関数の参照が変わったかどうかを確認できる
useEffect(() => {
console.log(
"メモ化していない関数の参照が変わったか:",
prevNonMemoFunc.current !== nonMemoFunc
);
console.log(
"メモ化した関数の参照が変わったか:",
prevMemoFunc.current !== memoFunc
);
//現在の関数参照を保存する
prevNonMemoFunc.current = nonMemoFunc;
prevMemoFunc.current = memoFunc;
});
return (
<div>
<input
type="text"
value={text}
onChange={(e) => setText(e.target.value)}
/>
</div>
);
}
テキストフィールドに何か入力することでステートを更新し、再レンダリングされるようにしています。
そこで、メモ化した関数・していない関数で参照先の関数が新しくなってしまっているか・いないかをコンソールで確認できるようにしました。↓(メモ化していない方は参照先を変更する必要がないにもかかわらず関数が新規作成され、参照先が変わっている)

以下のようにメモ化(useCallbackを利用)した関数「memoFunc」はコンポーネント内で再レンダリングが起きたとしてもreactによって新規作成されるのではなく、キャッシュされることで再利用できます。
const memoFunc = useCallback(() => {
console.log("メモ化関数が実行されたぜ!");
}, []);
今回は無理やり再レンダリングを起こし、特に意味のない関数でそれらがメモ化されている・されていないかを確認しました。実際は「再レンダリングが起きたとしても関数を新規作成するのではなく、キャッシュしておきたい、かつ描画パフォーマンスを落としている」というケースで登場するのがuseCallbackです。
自分はそこまで大規模なアプリケーションを開発したことがないので、レンダリングパフォーマンスが悪くなってしまうことにあまり遭遇したことがないですが、今後使う機会があったら本記事のことを思い出して使っていきたいなと思います。