カテゴリ: React 更新日: 2026/03/31

React Context APIのパフォーマンス最適化を徹底解説!useMemoで無駄な描画を防ぐ方法

Context APIのパフォーマンス最適化(useMemo活用)
Context APIのパフォーマンス最適化(useMemo活用)

先生と生徒の会話形式で理解しよう

生徒

「Reactのコンテキストを使ってみたんですけど、一箇所の数字を変えただけで画面全体が何度も作り直されているみたいで、動きがカクカクします。これって直せますか?」

先生

「それはパフォーマンスの低下が起きていますね。Reactにはユーズメモ(useMemo)という『計算結果を記憶する魔法』があります。これを使えば、無駄な作業を省いてサクサク動くようになりますよ。」

生徒

「ユーズメモ…難しそうですが、初心者の私でも使いこなせますか?」

先生

「大丈夫です。仕組みを身近な例えでお話ししますね。まずは、なぜ無駄な動きが発生するのか、その原因から見ていきましょう!」

1. Reactのレンダリングとコンテキストの悩み

1. Reactのレンダリングとコンテキストの悩み
1. Reactのレンダリングとコンテキストの悩み

Reactという道具を使ってWebサイトを作るとき、一番大切な動きが「レンダリング」です。レンダリングとは、画面のデータが書き換わったときに、新しい見た目を作り直して表示する作業のことです。例えば、ボタンを押して数字が1から2に変わったとき、Reactは画面を書き換えてくれます。

しかし、Context API(コンテキストエーピーアイ)という「共有の倉庫」を使っていると、困ったことが起こります。この倉庫の中身が少しでも変わると、その倉庫に関係している部品がすべて「念のため作り直そう!」と動き出してしまいます。本当は書き換える必要がない部品まで一緒に作り直されるため、これが積み重なるとパソコンやスマホの動作が重くなってしまうのです。これを解決するために、無駄な作業をさせない工夫が必要になります。

2. useMemoは「計算結果のメモ帳」

2. useMemoは「計算結果のメモ帳」
2. useMemoは「計算結果のメモ帳」

ここで登場するのが useMemo(ユーズメモ)です。これは簡単に言うと「結果を書き留めておくメモ帳」のようなものです。例えば、非常に複雑な計算問題があるとします。毎回ゼロから計算し直すのは大変ですが、一度計算した答えをメモ帳に書いておけば、次からはそのメモを見るだけで済みますよね。

Reactの世界でも同じです。前回の計算結果と、その計算に使う材料(依存配列と呼びます)を比べて、材料が変わっていなければ「計算し直さずに前の結果をそのまま使うよ!」とReactに教えてあげることができます。これが「パフォーマンス最適化」と呼ばれる、サイトを軽くするための重要な技術です。これを使うことで、コンテキストの倉庫が更新されても、特定の部品だけは以前の状態を保つことができるようになります。

3. useMemoを使わない場合の重い処理

3. useMemoを使わない場合の重い処理
3. useMemoを使わない場合の重い処理

まずは、最適化をしていない「重くなりやすいコード」を見てみましょう。この例では、ユーザー情報(名前)と、全く関係のないカウンター(数字)を同じ場所で管理しています。数字を増やすだけで、名前の表示部分まで不必要に反応してしまう状態です。


import React, { useState, createContext } from "react";

export const UserContext = createContext();

export function App() {
  const [count, setCount] = useState(0);
  const [name, setName] = useState("たろう");

  // ここで渡すデータが、毎回新しく作られてしまいます
  const value = { name, setName };

  return (
    <UserContext.Provider value={value}>
      <div>
        <button onClick={() => setCount(count + 1)}>
          数字を増やす(現在:{count})
        </button>
        <UserNameDisplay />
      </div>
    </UserContext.Provider>
  );
}

function UserNameDisplay() {
  console.log("名前の部品が再描画されました");
  return <div>ユーザー名:たろう</div>;
}
(ボタンを押して数字を増やすたびに、名前とは関係ないはずなのに「名前の部品が再描画されました」とログが出てしまいます。これが無駄な動きです。)

4. useMemoを導入して無駄を防ぐ書き方

4. useMemoを導入して無駄を防ぐ書き方
4. useMemoを導入して無駄を防ぐ書き方

それでは、先ほどの無駄を useMemo で解消してみましょう。書き方はとてもシンプルです。 `useMemo(() => 結果, [材料])` という形の中に、保存しておきたいデータを入れます。こうすることで、名前が変わったときだけ新しいデータを作り、数字が変わったときは前のデータを使い回すようになります。

プログラミング未経験の方は、「もし材料(名前)が変わっていなければ、前回の結果をそのまま使う」という約束を交わしているのだと考えてください。これにより、余計な部品の作り直しをピタリと止めることができます。


import React, { useState, createContext, useMemo } from "react";

export const UserContext = createContext();

export function App() {
  const [count, setCount] = useState(0);
  const [name, setName] = useState("たろう");

  // nameが変わったときだけ、新しいオブジェクトを作成します
  const value = useMemo(() => ({
    name,
    setName
  }), [name]); // ここに書いたものが変わらない限り、結果を再利用!

  return (
    <UserContext.Provider value={value}>
      <button onClick={() => setCount(count + 1)}>
        カウント:{count}
      </button>
      <UserNameDisplay />
    </UserContext.Provider>
  );
}
(今度はボタンを押しても、名前の部品は再描画されません。Reactが「あ、このデータは前と同じだから作り直さなくていいんだな」と判断してくれたおかげです。)

5. 依存配列(材料リスト)を正しく設定しよう

5. 依存配列(材料リスト)を正しく設定しよう
5. 依存配列(材料リスト)を正しく設定しよう

useMemoを使うときに一番気をつけなければならないのが、後ろにある `[]` の中身です。これは「依存配列(いぞんはいれつ)」と呼ばれます。ここには、計算に使うすべての変数を入れなければなりません。もし、必要な変数を入れ忘れてしまうと、データが変わったのに画面が古いまま、という不具合(バグ)が起きてしまいます。

例えば、名前だけでなく年齢も表示したい場合は、配列の中に名前と年齢の両方を入れます。こうすることで、「名前か年齢、どちらかが変わったら新しく作り直してね」という指示になります。逆に、何も入れたくない場合は空の配列 `[]` を使います。これは「最初の一回だけ計算して、あとはずっと同じものを使って」という意味になります。

6. オブジェクトの参照と同一性チェック

6. オブジェクトの参照と同一性チェック
6. オブジェクトの参照と同一性チェック

少し難しいお話をしますが、パソコンは「内容が同じ」であることと「同じ場所にあるデータ」であることを区別しています。例えば、中身が全く同じ二つのノートがあっても、それは別のノートですよね。JavaScript(ジャバスクリプト)という言語では、新しくデータ(オブジェクト)を作るたびに、内容が同じでも「新しい別のノート」として扱われます。

Reactのコンテキストは、この「新しいノートになったかどうか」をチェックして再描画を決めます。useMemoを使わないと、毎回「新しいノート」を渡してしまうため、中身が同じでもReactは「あ、新しいノートだ!作り直さなきゃ!」と勘違いしてしまいます。useMemoは「同じノートをずっと使い続ける」ためのテクニックなのです。


// 悪い例:レンダリングのたびに新しい「箱」が作られる
const value = { theme: "dark" };

// 良い例:一度作った「箱」を大切に使い回す
const value = useMemo(() => ({ theme: "dark" }), []);
(一見同じに見えますが、上は毎回新しい箱、下はずっと同じ箱を使い回すという大きな違いがあります。この違いが速さの秘密です。)

7. いつuseMemoを使うべきか

7. いつuseMemoを使うべきか
7. いつuseMemoを使うべきか

「じゃあ全部の場所にuseMemoを使えばいいの?」と思うかもしれませんが、実はそうではありません。メモを取ること自体にも、ほんの少しだけ手間(コスト)がかかるからです。メモ帳を用意して、以前のものと比較して…という作業を、あまりにも単純な場所で行うと、かえって効率が悪くなることもあります。

使うべき目安は、以下の二つのパターンです。一つは「計算にすごく時間がかかる処理」をするとき。もう一つは、今回のコンテキストのように「そのデータがたくさんの部品に配られるとき」です。特にコンテキストの `value` に渡すデータは、多くの部品に影響を与えるため、積極的に useMemo を使って最適化するのがプロの現場での常識となっています。

8. コンテキスト最適化の仕上げ:複数の値を渡すとき

8. コンテキスト最適化の仕上げ:複数の値を渡すとき
8. コンテキスト最適化の仕上げ:複数の値を渡すとき

実際の開発では、一つのコンテキストで「今の設定値」と「設定を変える関数」の両方を渡すことが多いです。このとき、二つをまとめて一つのオブジェクト(情報の塊)にすることが一般的ですが、ここが最も最適化が必要なポイントになります。以下の完成形を参考に、サクサク動くアプリの土台を作ってみましょう。


import React, { createContext, useState, useMemo, useContext } from "react";

const ThemeContext = createContext();

export function ThemeProvider({ children }) {
  const [isDark, setIsDark] = useState(false);

  // 切り替え関数と状態を一つのオブジェクトにまとめ、useMemoで保護する
  const themeData = useMemo(() => ({
    isDark,
    toggleTheme: () => setIsDark(prev => !prev)
  }), [isDark]); // isDarkが変わったときだけ新しくする

  return (
    <ThemeContext.Provider value={themeData}>
      {children}
    </ThemeContext.Provider>
  );
}

// 使うときは、useContextを呼び出すだけ!
function ThemeButton() {
  const { isDark, toggleTheme } = useContext(ThemeContext);
  return (
    <button onClick={toggleTheme}>
      {isDark ? "明るいモードへ" : "暗いモードへ"}
    </button>
  );
}
(このように、Provider側でしっかりとuseMemoを使っておけば、これを使う側の部品(ThemeButtonなど)は、必要なときだけ賢く動いてくれるようになります。)
カテゴリの一覧へ
新着記事
New1
React
React Context APIのパフォーマンス最適化を徹底解説!useMemoで無駄な描画を防ぐ方法
New2
React
ReactのProps必須・オプショナル指定を完全解説!初心者でもわかる型安全なProps管理
New3
React
Reactでデフォルト動作を止める!preventDefaultの使い方を初心者向けに解説
New4
Next.js
Next.js ISR(Incremental Static Regeneration)が必要になるケースを初心者向けに解説
人気記事
No.1
Java&Spring記事人気No1
React
Reactの子コンポーネントから親コンポーネントへデータを渡す方法を徹底解説!初心者にもわかるReactのイベントとデータの流れ
No.2
Java&Spring記事人気No2
React
Reactとは?初心者でもわかるReact.jsの基本概念と特徴をやさしく解説
No.3
Java&Spring記事人気No3
React
React開発におすすめのVSCode拡張機能まとめ!初心者でもすぐ使える便利ツール紹介
No.4
Java&Spring記事人気No4
React
ReactのContext APIとReduxの違いを初心者向けに徹底比較!どちらを使うべきか完全解説
No.5
Java&Spring記事人気No5
React
ReactのState管理ベストプラクティス!初心者でもわかる再レンダリング最適化の考え方
No.6
Java&Spring記事人気No6
React
React(TypeScript)で学ぶStateの型推論と型指定の違い!型安全なState管理を初心者向けにやさしく解説
No.7
Java&Spring記事人気No7
Next.js
Next.jsのSSR(Server Side Rendering)入門!Pages Routerとの違いを初心者向けに解説
No.8
Java&Spring記事人気No8
Next.js
Next.jsのServer ComponentsとClient Componentsの通信方法を完全解説!props渡しの基本と使い方