React における useMemo
と useCallback
の違いと効果的な使い方
フロントエンド開発をしていると、状態管理や再レンダリングの制御に頭を悩ませることが多いです。
特にコンポーネントの再レンダリングが頻発するとパフォーマンスに影響が出るため、React Hooks の中でも useMemo
と useCallback
は必須のテクニックとなります。
1. useMemo
とは
- 目的:計算コストの高い処理結果をメモ化し、依存値が変わらない限り再計算を防ぐ
- 構文:
const memoizedValue = useMemo(() => { // 高コストな計算 return computeExpensiveValue(a, b); }, [a, b]);
使いどころ
- 大量データのフィルタリング/ソート結果
- 複雑な演算を伴う値の生成
使い方例
import { useMemo } from "react";
function PriceList({ prices }: { prices: number[] }) {
// 毎レンダーで行うと重いソート処理をメモ化
const sorted = useMemo(() => {
return [...prices].sort((a, b) => a - b);
}, [prices]);
return (
<ul>
{sorted.map((p) => (
<li key={p}>¥{p.toLocaleString()}</li>
))}
</ul>
);
}
2. useCallback とは
-
目的:関数をメモ化し、依存値が変わらない限り同一インスタンスを再利用する
-
構文:
const memoizedCallback = useCallback(() => {
doSomething(value);
}, [value]);
使いどころ
- 子コンポーネントへのプロップスとして渡すコールバック
- 再レンダー時に毎回新しい関数を生成したくない場合
使い方例
import { useState, useCallback } from "react";
function Counter() {
const [count, setCount] = useState(0);
// setCount だけが変わったときに再定義
const increment = useCallback(() => {
setCount((c) => c + 1);
}, []);
return <button onClick={increment}>Count: {count}</button>;
}
3. useMemo vs useCallback
- 項目 useMemo useCallback
- メモ化対象 値 関数
- 戻り値 計算結果(任意の型) コールバック関数
- 主な用途 重い計算結果の再利用 再レンダー時に同一関数を渡す
4. 注意点
-
乱用に注意
-
小さな処理をメモ化するとオーバーヘッドのほうが大きくなることも
-
依存配列を正しく管理
-
依存配列を空にすると最新の値を参照できなくなるケースあり
-
プリミティブ以外の依存
-
オブジェクトや配列を依存に入れる場合は要注意(毎回異なる参照になるとメモ化無意味)
5. まとめ
-
useMemo は値の重い計算を防ぐ
-
useCallback はコールバック関数の再生成を防ぐ
-
どちらもパフォーマンス改善に有効だが、過剰な使用は逆効果
-
依存配列を正しく管理し、必要な場所でのみ使うのがベストプラクティス