T-CREATOR

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

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.memouseMemo を組み合わせると、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

もっと見る