カテゴリ: React 更新日: 2026/04/01

React Context APIの分割方法を解説!パフォーマンスを高めるベストプラクティス

Contextを分割して使うベストプラクティス
Contextを分割して使うベストプラクティス

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

生徒

「Reactのコンテキストを使ってみましたが、一つの箱に全部のデータを入れると、関係ない部品まで動き出して重くなるって本当ですか?」

先生

「その通りです。大きすぎる箱は効率が悪くなるので、役割ごとに箱を分けるのがベストプラクティスとされています。」

生徒

「箱を分ける…?どうやって使い分ければいいのか、具体的に教えてください!」

先生

「コンテキストを適切に分割することで、無駄な再描画を防ぎ、保守性の高いコードが書けるようになります。実際の作り方を見ていきましょう!」

1. なぜReactのコンテキストを分割する必要があるのか?

1. なぜReactのコンテキストを分割する必要があるのか?
1. なぜReactのコンテキストを分割する必要があるのか?

Reactの Context API(コンテキストエーピーアイ)は、複数の部品で共有したいデータを管理する「共通の倉庫」のようなものです。非常に便利ですが、初心者が陥りやすい罠があります。それは、ユーザー情報、画面の色設定、買い物かごの中身など、種類の違うすべてのデータを一つの大きな倉庫に詰め込んでしまうことです。

Reactには「コンテキストの値が一つでも変わると、そのコンテキストを参照している部品がすべて描き直される(レンダリングされる)」というルールがあります。そのため、画面の色を変えただけなのに、全く関係のないユーザー名の表示部品まで描き直されてしまいます。これを防ぐために、役割ごとに倉庫を分ける「分割」が必要になるのです。

2. コンテキストを分けるメリットと「関心の分離」

2. コンテキストを分けるメリットと「関心の分離」
2. コンテキストを分けるメリットと「関心の分離」

コンテキストを分割することを、プログラミングの世界では「関心の分離」と呼びます。これは「似ていない役割のものは、別々に管理する」という考え方です。例えば、料理をするときに冷蔵庫の中に服や本が入っていたら使いにくいですよね。それと同じで、プログラムも「ユーザーに関するもの」と「アプリの設定に関するもの」を分けることで、格段に扱いやすくなります。

分割することのメリットは主に二つあります。一つは「パフォーマンスの向上」です。必要なデータだけが更新されるので、パソコンやスマートフォンの動作が軽くなります。もう一つは「管理のしやすさ」です。不具合が起きたときに、どの倉庫を確認すれば良いのかがすぐに見つかるようになります。

3. 役割別に複数のコンテキストを作成する方法

3. 役割別に複数のコンテキストを作成する方法
3. 役割別に複数のコンテキストを作成する方法

それでは、具体的に二つのコンテキスト(ユーザー情報とテーマ設定)を別々に作成するコードを見てみましょう。createContext(クリエイトコンテキスト)という命令を使って、必要な数だけ倉庫の定義を作ります。


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

// 1. ユーザー情報のための倉庫を定義
export const UserContext = createContext();

// 2. テーマ(色)設定のための倉庫を定義
export const ThemeContext = createContext();

export function AppProviders({ children }) {
  const [user, setUser] = useState({ name: "たろう" });
  const [isDark, setIsDark] = useState(false);

  return (
    <UserContext.Provider value={{ user, setUser }}>
      <ThemeContext.Provider value={{ isDark, setIsDark }}>
        {children}
      </ThemeContext.Provider>
    </UserContext.Provider>
  );
}
(UserContext と ThemeContext という二つの異なる倉庫ができました。これで、ユーザー情報を変更してもテーマ設定を見ている部品には影響が出ません。)

4. プロバイダーをネスト(重ね書き)する構成

4. プロバイダーをネスト(重ね書き)する構成
4. プロバイダーをネスト(重ね書き)する構成

先ほどのコードでは、二つの Provider(プロバイダー)を重ねて書いていました。プロバイダーとは、倉庫のデータを配る役割を持つ部品のことです。このように重ねて書くことを「ネストする」と言います。

この構成にすることで、内側にある children(チルドレン:アプリ全体の部品)は、外側にあるすべての倉庫にアクセスできるようになります。パソコンを触ったことがない方でも、マトリョーシカ人形のように、大きな箱の中に小さな箱が入っていて、一番内側からはすべての箱の中身が見える様子をイメージすると分かりやすいでしょう。

5. 特定のコンテキストだけを呼び出す部品の作り方

5. 特定のコンテキストだけを呼び出す部品の作り方
5. 特定のコンテキストだけを呼び出す部品の作り方

倉庫が分かれているので、使う側も必要なものだけを選んで受け取ることができます。useContext(ユーズコンテキスト)を使って、どの倉庫からデータを取り出すかを指定します。これにより、無駄な再描画が発生しない効率的な部品になります。


import React, { useContext } from "react";
import { ThemeContext } from "./App";

function ColorToggle() {
  // テーマの倉庫から、現在の設定と変更用の関数だけを取り出します
  const { isDark, setIsDark } = useContext(ThemeContext);

  return (
    <button onClick={() => setIsDark(!isDark)}>
      モード切替: {isDark ? "ダーク" : "ライト"}
    </button>
  );
}
(このボタン部品はテーマの倉庫しか見ていないため、ユーザー名の情報がどれだけ更新されても、このボタンが不必要に動き出すことはありません。)

6. 状態と更新用関数を別々のコンテキストにする技

6. 状態と更新用関数を別々のコンテキストにする技
6. 状態と更新用関数を別々のコンテキストにする技

さらに高度なベストプラクティスとして、「現在の値」と「値を変更する命令(関数)」さえも別のコンテキストに分ける手法があります。これは、データの変更命令だけを出したい部品が、データの変化自体に反応して描き直されるのを防ぐためです。

例えば、今の数値を見たい部品と、リセットボタンだけの部品を分けるような場合です。リセットボタンは「リセットせよ」という命令を送るだけでよく、今の数値がいくらであるかを知る必要はありません。これを分けることで、真のパフォーマンス最適化が実現します。


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

const StateContext = createContext();
const DispatchContext = createContext();

export function CounterProvider({ children }) {
  const [count, setCount] = useState(0);

  return (
    <StateContext.Provider value={count}>
      <DispatchContext.Provider value={setCount}>
        {children}
      </DispatchContext.Provider>
    </StateContext.Provider>
  );
}
(State(状態)と Dispatch(命令)を分離しました。これにより、命令を送るだけの部品は、状態が変わっても再描画されることがなくなります。)

7. コンテキスト分割を整理する「カスタムフック」

7. コンテキスト分割を整理する「カスタムフック」
7. コンテキスト分割を整理する「カスタムフック」

コンテキストの数が増えてくると、使う側の部品で何度も useContext を書くのが大変になります。そこで、独自の便利な命令セットである「カスタムフック」を作っておくのがプロの技です。

カスタムフックを作ることで、倉庫の名前を意識せずに「ユーザー情報をください」とお願いするだけでデータが手に入るようになります。これにより、将来的にプログラムの構造が変わったとしても、修正する場所を最小限に抑えることができます。


import { useContext } from "react";
import { UserContext } from "./App";

// 独自の便利な命令(カスタムフック)
export function useUser() {
  const context = useContext(UserContext);
  if (context === undefined) {
    throw new Error("UserProviderの中で使ってください");
  }
  return context;
}
(部品の中では useUser() と書くだけでよくなります。倉庫の場所を覚える必要がなくなり、コードがとてもスッキリします。)

8. 分割されたコンテキストをまとめるコンポーネント

8. 分割されたコンテキストをまとめるコンポーネント
8. 分割されたコンテキストをまとめるコンポーネント

たくさんのプロバイダーが重なると、メインのプログラムが見づらくなってしまいます。ベストプラクティスでは、これらを一つにまとめた「ラッパー部品」を作ります。これにより、アプリの入り口を綺麗に保つことができます。

プログラミング未経験の方は、たくさんの延長コードを一つの電源タップにまとめるイメージを持ってください。スッキリと整理された環境は、バグ(間違い)を減らす第一歩になります。今回の分割テクニックを活用して、サクサクと快適に動くReactアプリを目指しましょう!

カテゴリの一覧へ
新着記事
New1
React
ReactのPropsでオブジェクト型を扱う方法を完全ガイド!初心者でもわかる型安全なProps管理
New2
React
Reactの条件分岐の使い方を完全ガイド!初心者でもわかるReactの条件分岐
New3
React
React Context APIの分割方法を解説!パフォーマンスを高めるベストプラクティス
New4
React
Reactの自己終了タグの書き方を完全ガイド!初心者でもわかるimgやinputのJSX記法
人気記事
No.1
Java&Spring記事人気No1
React
Reactの子コンポーネントから親コンポーネントへデータを渡す方法を徹底解説!初心者にもわかるReactのイベントとデータの流れ
No.2
Java&Spring記事人気No2
React
Reactの学習ロードマップ!初心者が最短で習得する流れを完全ガイド
No.3
Java&Spring記事人気No3
React
Reactとは?初心者でもわかるReact.jsの基本概念と特徴をやさしく解説
No.4
Java&Spring記事人気No4
React
ReactとTypeScriptの環境構築をやさしく解説!Viteとtsconfigの設定も丁寧に紹介
No.5
Java&Spring記事人気No5
React
React開発におすすめのVSCode拡張機能まとめ!初心者でもすぐ使える便利ツール紹介
No.6
Java&Spring記事人気No6
React
ReactのState管理ベストプラクティス!初心者でもわかる再レンダリング最適化の考え方
No.7
Java&Spring記事人気No7
React
ReactのContext APIでログイン状態を管理する方法を完全解説!初心者でもわかる認証機能の実装
No.8
Java&Spring記事人気No8
Next.js
Next.jsのSSR(Server Side Rendering)入門!Pages Routerとの違いを初心者向けに解説