使い方
1. 子コンポーネントへ渡す関数を固定
const handleClick = React.useCallback(() => setCount(c => c + 1), []);
- 空の依存配列
[]
で 常に同じ関数参照 を渡し、子の無駄な再レンダーを防ぎます。
2. 依存値が変わるときだけ新しい関数
const fetchData = React.useCallback(() => api(id), [id]);
-
id
が変わったときだけ関数を作り直し、不要な再生成を減らします。
useCallback の役割
毎回作られがちな 関数をメモ化 し、再レンダーを軽くするフックです。
-
関数参照を安定させる
子に渡しても再レンダーが起きにくい。 -
パフォーマンスを守る
重い計算や副作用を含む関数の再生成を防ぐ。 -
依存配列で制御できる
どの値が変わったら新しい関数にするか宣言できる。
関数参照を安定させるとは?
React は props の 参照が変わるだけで 子コンポーネントを再描画します。
とくに onClick
などのコールバックはレンダーごとに新しくなるため、子が頻繁に再描画される原因に。
useCallback
に包めば 同じ参照 を保てるので、子側は余計な更新をスキップできます。
例:リストアイテムが無駄に再レンダーしないボタン
// Item.jsx
import React from "react";
export const Item = React.memo(function Item({ label, onAdd }) {
console.log("render", label); // レンダー回数チェック
return <button onClick={onAdd}>{label}</button>;
});
// App.jsx
import React from "react";
import { Item } from "./Item";
export default function App() {
const [count, setCount] = React.useState(0);
// useCallback で関数参照を固定
const handleAdd = React.useCallback(() => setCount(c => c + 1), []);
return (
<div>
<p>合計: {count}</p>
{/* Item は onAdd の参照が変わらないので再レンダーしない */}
<Item label="追加" onAdd={handleAdd} />
</div>
);
}
useCallback のベストプラクティス
-
安易に多用しない
軽い関数を包むと逆にオーバーヘッド。子がReact.memo
などで最適化されている場合に使う。 -
依存配列を正確に書く
使っている値を漏れなく並べる。漏れると古い値を掴んでバグになる。