ReactのuseMemoとは?再レンダリングを防ぐための基本と使い方をわかりやすく解説

Reactアプリケーションが成長するにつれて、パフォーマンスの低下が気になる場面が増えてきます。
とくに、毎回同じ結果しか返さない計算処理や再生成されるオブジェクトや関数が原因で、意図しない再レンダリングが発生してしまうことも少なくありません。
そんな問題を解決するために活躍するのが、Reactの useMemo
フックです。
このフックを正しく使いこなすことで、不要な再レンダリングを防ぎ、効率的なコンポーネント構成を実現できます。
本記事では、React初心者の方でもわかりやすいように、基本的な仕組みから応用的な使い方までを丁寧に解説いたします。
公式ドキュメントへのリンクも適宜挿入しながら、手を動かしながら学べる内容となっております。
パフォーマンス最適化に欠かせないuseMemoの基礎知識
useMemo
は、計算結果の「メモ化(記憶)」を行うReactのフックです。
コンポーネントの再レンダリング時に、毎回重い計算を行うのではなく、依存する値が変わらない限りは前回の計算結果を再利用します。
基本構文
tsxconst memoizedValue = useMemo(() => {
return heavyCalculation(a, b);
}, [a, b]);
この構文では、a
またはb
が変わらない限り、heavyCalculation(a, b)
は再評価されません。
公式ドキュメントより
useMemo
lets you cache the result of a calculation between re-renders.
React: useMemo – Official Docs
実践:useMemoを使ったパフォーマンス改善例
例:重い計算処理のメモ化
tsxconst heavyCalc = (num: number): number => {
console.log('重い計算中...');
let result = 0;
for (let i = 0; i < 1000000000; i++) {
result += num * Math.random();
}
return result;
};
const App = () => {
const [count, setCount] = useState(0);
const [other, setOther] = useState(false);
const memoizedResult = useMemo(() => heavyCalc(count), [count]);
return (
<div>
<p>計算結果: {memoizedResult}</p>
<button onClick={() => setCount(count + 1)}>カウント</button>
<button onClick={() => setOther(!other)}>その他</button>
</div>
);
};
このコードでは、「その他」ボタンを押しても heavyCalc
は呼ばれません。
count
が変わったときのみ再計算されます。
なぜuseMemoが必要なのか?
Reactでは、関数コンポーネントは再レンダリングのたびに関数全体が再実行されるという仕様があります。
そのため、以下のようなケースでは無駄な処理が実行されてしまいます。
- 重い計算処理
- 毎回新しいオブジェクトや配列を生成
- コンポーネント間で同じデータをpropsとして渡す
useMemo
を使うことで、これらの処理結果をキャッシュして、無駄なコストを削減できます。
useMemoとReact.memoの違い
フック | 概要 | 主な使用対象 | メモ化の対象 |
---|---|---|---|
useMemo | 計算結果をメモ化する | 値(オブジェクト、配列など) | 値(任意の型) |
React.memo | コンポーネント自体のレンダリングをスキップ | コンポーネント | コンポーネント |
これらは併用することで、より強力な最適化が可能になります。
useMemoの使いすぎに注意
useMemo
自体にもオーバーヘッドがあります。
以下のような場面では使用を避けるのが賢明です。
- 処理が軽い計算や単純な値
- 小規模なコンポーネント
- 見た目上影響が少ないUI部品
Profilerなどでボトルネックを確認してから導入するのがベストです。
オブジェクトや配列をpropsとして渡す際のテクニック
オブジェクトや配列は毎回新しいインスタンスとして生成されると、子コンポーネントの React.memo
が効果を発揮しません。
悪い例
tsx<Child filters={{ category: 'tech' }} />
これは毎回新しいオブジェクトとして扱われます。
良い例
tsxconst filters = useMemo(() => ({ category: 'tech' }), []);
<Child filters={filters} />
このように useMemo
でラップすることで、propsの再評価を防げます。
React.memoとの併用パターン
React.memo
と useMemo
を組み合わせると、propsの値が変わらない限り、コンポーネントが再描画されない状態を保てます。
tsxconst config = useMemo(() => ({ darkMode: theme === 'dark' }), [theme]);
<Child config={config} />
さらに React.memo
の第二引数としてカスタム比較関数を渡せば、より柔軟な最適化が可能です。
useCallbackとの違いと使い分け
フック | メモ化対象 | 用途 |
---|---|---|
useMemo | 値(オブジェクトなど) | 計算結果のキャッシュ |
useCallback | 関数 | 関数の再生成防止 |
関数を子に渡す場合は useCallback
、値を渡すなら useMemo
を選ぶとよいでしょう。
状態管理ライブラリとの連携
ReduxやZustandなどの外部ステート管理ライブラリでも、セレクタの結果をオブジェクトでまとめる場合は useMemo
でのメモ化が有効です。
tsxconst config = useMemo(() => ({ darkMode, themeColor }), [darkMode, themeColor]);
Zustandでは shallow
比較を活用することで、再レンダリングを抑える設計も可能です。
ProfilerでuseMemoの効果を確認する
React DevToolsの「Profiler」タブを使えば、どのコンポーネントがいつ再描画されているかを可視化できます。
これにより useMemo
の効果が一目でわかり、不要な最適化や足りない工夫に気づけるようになります。
よくある質問
-
Q: useMemoは毎回使うべきですか?
A: いいえ。コストの高い処理にのみ限定するべきです。 -
Q: useMemoの戻り値が関数でもいいですか?
A: はい。ただし関数をメモ化したい場合はuseCallback
の方が適しています。 -
Q: SSRでは有効ですか?
A: SSR中は毎回初期化されるため、クライアントマウント後にのみ有効です。
useMemo活用のまとめ
チェック項目 | ポイント |
---|---|
計算コストの有無 | 重い処理なら使う |
オブジェクト・配列の安定性 | useMemoで参照を固定 |
React.memoやuseCallbackとの併用 | 再レンダリングを防ぐために必須 |
Profilerによる実測 | オーバーヘッドが逆効果になっていないか確認すること |
おわりに
useMemo
は、Reactのパフォーマンス最適化における重要な武器です。
ですが、使いどころを間違えると効果が出ないばかりか、逆に処理の遅延や複雑さを生むこともあります。
本記事を通じて、useMemo
の役割と正しい活用法を理解し、Reactアプリの品質向上にお役立ていただければ幸いです。
Reactの内部挙動に目を向け、**「なぜ再描画されるのか?」**を理解しながら、最適な設計を目指してまいりましょう。
記事Article
もっと見る- article
React Suspense入門:非同期UIを直感的に書ける新しいアプローチとは?
- article
useCallbackとは?再レンダリングを防ぐための基本と使い方をわかりやすく解説
- article
開発時にで役立つgit stashコマンドの基本と応用テクニックを紹介
- article
React.memoとは?再レンダリングを防ぐための基本と使い方をわかりやすく解説
- article
Reactの再レンダリングを制御する!memo・useMemo・useCallbackの使い分けを紹介
- article
Reactの状態管理2025:「useState」「Redux Toolkit」「Jotai」「Zustand」を比較してみた