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

Reactで複数のContextを組み合わせる方法を完全解説!初心者でもわかるContext APIの応用

複数のContextを組み合わせる方法
複数のContextを組み合わせる方法

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

生徒

「Context APIってひとつしか使えないんですか?テーマとログイン情報を両方管理したいんですけど。」

先生

「Contextはいくつでも作れますし、複数を同時に使うこともできます。目的ごとに分けて管理するのが実際の開発でも一般的なやり方です。」

生徒

「複数のContextをまとめて使うとき、書き方が複雑にならないか心配です。」

先生

「コツをつかめばシンプルに書けます。実際のコードを見ながら順番に確認していきましょう!」

1. なぜ複数のContextを使うのか?ひとつにまとめてはいけない理由

1. なぜ複数のContextを使うのか?ひとつにまとめてはいけない理由
1. なぜ複数のContextを使うのか?ひとつにまとめてはいけない理由

Context APIを使い始めると、「すべてのデータをひとつのContextにまとめてしまえば楽では?」と思うことがあります。しかし実際の開発では、用途ごとにContextを分けるのが一般的で、その理由を理解しておくことが大切です。

まず、Contextの値が変わると、そのContextを使っているすべてのコンポーネントが再描画されます。再描画(再レンダリング)とは、コンポーネントが最新の状態を反映するために再計算されて画面が更新されることです。すべてのデータをひとつのContextにまとめると、どれかひとつのデータが変わっただけで、そのContextを参照しているすべてのコンポーネントが更新されてしまいます。

また、ひとつのContextにたくさんのデータが入るとコードが読みにくくなり、どのデータがどこで使われているか把握しにくくなります。ログイン情報はユーザーContext、テーマ設定はテーマContext、言語設定は言語Contextというように、役割ごとに分けることでコードが整理されて管理しやすくなります。

2. 複数のContextをProviderで入れ子にする基本的な書き方

2. 複数のContextをProviderで入れ子にする基本的な書き方
2. 複数のContextをProviderで入れ子にする基本的な書き方

複数のContextを使うときは、それぞれのProviderを入れ子にして使います。入れ子(ネスト)とは、コンポーネントの中にさらにコンポーネントを入れることです。内側にあるコンポーネントはすべての親Providerのデータにアクセスできます。

まずはテーマと言語のふたつのContextを作って組み合わせるシンプルな例を見てみましょう。


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

// テーマ用のContextを作成
const ThemeContext = createContext("light");
// 言語用のContextを作成
const LangContext = createContext("ja");

function App() {
  return (
    // 複数のProviderを入れ子にする
    <ThemeContext.Provider value="dark">
      <LangContext.Provider value="en">
        <MainPage />
      </LangContext.Provider>
    </ThemeContext.Provider>
  );
}

function MainPage() {
  // ふたつのContextからそれぞれデータを取り出す
  const theme = useContext(ThemeContext);
  const lang = useContext(LangContext);

  return (
    <div style={{ background: theme === "dark" ? "#222" : "#fff", color: theme === "dark" ? "#fff" : "#000", padding: "16px" }}>
      <p>テーマ:{theme}</p>
      <p>言語:{lang}</p>
    </div>
  );
}

export default App;
画面が暗い背景に白い文字で表示され、「テーマ:dark」「言語:en」と表示されます。MainPageはThemeContextとLangContextのどちらからもuseContextでデータを取り出しています。

複数のContextを使うときも、useContextを複数回呼び出すだけで、それぞれのContextからデータを取得できます。Providerの順番に決まりはありませんが、外側のProviderのほうが広い範囲に影響を与えます。

3. useStateと組み合わせて複数のContextで状態を管理しよう

3. useStateと組み合わせて複数のContextで状態を管理しよう
3. useStateと組み合わせて複数のContextで状態を管理しよう

実際のアプリでは、Contextのデータが変化する場合がほとんどです。useStateと組み合わせることで、それぞれのContextの状態を独立して管理できます。テーマの切り替えとログイン状態の管理を別々のContextで行う例を見てみましょう。


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

const ThemeContext = createContext(null);
const AuthContext = createContext(null);

function App() {
  const [theme, setTheme] = useState("light");
  const [isLoggedIn, setIsLoggedIn] = useState(false);

  return (
    <ThemeContext.Provider value={{ theme, setTheme }}>
      <AuthContext.Provider value={{ isLoggedIn, setIsLoggedIn }}>
        <ControlPanel />
      </AuthContext.Provider>
    </ThemeContext.Provider>
  );
}

function ControlPanel() {
  const { theme, setTheme } = useContext(ThemeContext);
  const { isLoggedIn, setIsLoggedIn } = useContext(AuthContext);

  return (
    <div style={{ background: theme === "dark" ? "#333" : "#f0f0f0", padding: "20px" }}>
      <p>テーマ:{theme}</p>
      <p>ログイン状態:{isLoggedIn ? "ログイン中" : "未ログイン"}</p>
      <button onClick={() => setTheme(theme === "light" ? "dark" : "light")}>
        テーマを切り替える
      </button>
      <button onClick={() => setIsLoggedIn(!isLoggedIn)}>
        {isLoggedIn ? "ログアウト" : "ログイン"}
      </button>
    </div>
  );
}

export default App;
画面にテーマ状態とログイン状態が表示されます。「テーマを切り替える」ボタンでlightとdarkが交互に切り替わり、「ログイン」ボタンを押すとログイン中になります。ふたつの状態はそれぞれ独立したContextで管理されています。

テーマが変わってもAuthContextを使っているコンポーネントには影響が出ず、ログイン状態が変わってもThemeContextだけを使っているコンポーネントには影響が出ません。Contextを分けておくことでこのような独立性が保たれます。

4. Contextをファイルに分けて複数管理をスッキリさせよう

4. Contextをファイルに分けて複数管理をスッキリさせよう
4. Contextをファイルに分けて複数管理をスッキリさせよう

複数のContextを使うと、App.jsxに定義が集中してコードが長くなりがちです。実際の開発では、それぞれのContextを専用のファイルに切り出して管理するのが一般的です。

ここでは通知メッセージを管理するContextをファイルに切り出す例を紹介します。


// NoticeContext.jsx
import { createContext, useContext, useState } from "react";

export const NoticeContext = createContext(null);

// カスタムフック:useContextをラップして使いやすくする
export function useNotice() {
  return useContext(NoticeContext);
}

// Providerコンポーネントをエクスポート
export function NoticeProvider({ children }) {
  const [notices, setNotices] = useState([]);

  const addNotice = (text) => {
    setNotices((prev) => [...prev, text]);
  };

  const clearNotices = () => {
    setNotices([]);
  };

  return (
    <NoticeContext.Provider value={{ notices, addNotice, clearNotices }}>
      {children}
    </NoticeContext.Provider>
  );
}
このファイル単体では画面に何も表示されません。NoticeProvider、useNotice、NoticeContextの3つをエクスポートしておくことで、アプリのどこからでも簡単にインポートして使えます。

カスタムフックとは、useContextなどのフックをラップして独自に作った関数のことです。useNotice()と書くだけでContextのデータが取得できるようになるため、毎回useContext(NoticeContext)と長く書く手間が省けます。

このようにContextごとに専用ファイルを作ると、contexts/NoticeContext.jsxcontexts/ThemeContext.jsxのように整理でき、どのファイルが何を管理しているかが一目でわかるようになります。

5. 複数のProviderをひとつにまとめるコンポーネントの作り方

5. 複数のProviderをひとつにまとめるコンポーネントの作り方
5. 複数のProviderをひとつにまとめるコンポーネントの作り方

Contextが増えてくると、App.jsxでProviderを何重にも入れ子にするコードが長くなってきます。そこでよく使われるのが、すべてのProviderをひとつのコンポーネントにまとめる方法です。AppProvidersなどの名前でまとめることが多いです。


import React from "react";
import { ThemeProvider } from "./contexts/ThemeContext";
import { NoticeProvider } from "./contexts/NoticeContext";
import { AuthProvider } from "./contexts/AuthContext";

// すべてのProviderをひとつにまとめるコンポーネント
function AppProviders({ children }) {
  return (
    <AuthProvider>
      <ThemeProvider>
        <NoticeProvider>
          {children}
        </NoticeProvider>
      </ThemeProvider>
    </AuthProvider>
  );
}

function App() {
  return (
    // AppProvidersひとつで囲むだけでOK
    <AppProviders>
      <MainContent />
    </AppProviders>
  );
}

function MainContent() {
  return <p>アプリのメインコンテンツ</p>;
}

export default App;
画面に「アプリのメインコンテンツ」と表示されます。App.jsxの中はAppProvidersで囲むだけになり、Provider関連の定義はすべてAppProvidersファイルにまとまっています。

AppProvidersをひとつ作っておくことで、App.jsxはとてもすっきりした状態を保てます。Providerを追加したいときはAppProvidersに追加するだけなので、変更箇所も一か所にまとまります。アプリが大きくなるほど、この整理の効果を実感できます。

6. 複数のContextを使うときの設計の考え方とよくある失敗

6. 複数のContextを使うときの設計の考え方とよくある失敗
6. 複数のContextを使うときの設計の考え方とよくある失敗

複数のContextを運用するうえで、設計の考え方をあらかじめ知っておくと、後から困ることが減ります。

まず大切なのは、Contextに入れるデータの責任範囲をはっきり決めることです。たとえば「ユーザー情報Context」にはログインユーザーのデータだけを入れ、通知やテーマを混在させないようにします。責任範囲が明確だと、デバッグのときにどのContextを確認すればいいかがすぐわかります。

次によくある失敗として、更新頻度の高いデータと低いデータを同じContextに入れてしまうケースがあります。たとえば1秒ごとに変わるカウンターと、めったに変わらないユーザー名を同じContextに入れると、カウンターが変わるたびにユーザー名を使っているコンポーネントまで再描画されます。更新頻度の違うデータは別のContextに分けることが、パフォーマンスを保つうえで重要です。

また、Context APIで管理する必要がないデータまでContextに入れてしまうことも避けましょう。コンポーネント内だけで使うデータはuseStateで十分です。Context APIはあくまで複数のコンポーネントをまたいで共有する必要があるデータに使うのが正しい使い方です。

7. 複数のContextを活用した実践的なアプリの構成イメージ

7. 複数のContextを活用した実践的なアプリの構成イメージ
7. 複数のContextを活用した実践的なアプリの構成イメージ

実際のWebアプリではどのようにContextを使い分けているのか、よく見られる構成パターンを紹介します。

たとえばECサイト(オンラインショッピングサイト)であれば、次のように役割ごとにContextを分けるのが一般的です。AuthContextでログイン状態とユーザー情報を管理します。CartContextでカートの中身と操作関数を管理します。ThemeContextでダークモードやライトモードの切り替えを管理します。NotificationContextで画面上部に表示するお知らせメッセージを管理します。

これらをAppProvidersにまとめておくことで、App.jsx自体はとてもシンプルな構成を保てます。新しい機能を追加するときも、新しいContextファイルを作ってAppProvidersに追加するだけなので、既存のコードへの影響を最小限に抑えながら機能を拡張できます。

Contextをうまく分けて管理する習慣をつけると、アプリが大きくなってもコードの見通しを保てます。最初から完璧な設計を目指す必要はなく、使いながら少しずつ整理していくのが現実的なアプローチです。

カテゴリの一覧へ
新着記事
New1
React
Reactで複数のContextを組み合わせる方法を完全解説!初心者でもわかるContext APIの応用
New2
React
ReactでStateリフトアップ(Lifting State Up)の実践方法をやさしく解説!Propsで親子間をつなぐ設計
New3
React
Fetch APIでPUT・DELETEを実行する方法をやさしく解説!初心者でもできるReactのサーバー通信
New4
Next.js
Next.jsのダッシュボード構造におけるLayout設計を徹底解説!初心者でも理解できるLayoutとTemplateの使い方
人気記事
No.1
Java&Spring記事人気No1
React
Reactとは?初心者でもわかるReact.jsの基本概念と特徴をやさしく解説
No.2
Java&Spring記事人気No2
React
ReactとTypeScriptの環境構築をやさしく解説!Viteとtsconfigの設定も丁寧に紹介
No.3
Java&Spring記事人気No3
React
ReactのJSXとJavaScriptの違いを完全ガイド!初心者でもわかるReactのJSX入門
No.4
Java&Spring記事人気No4
Next.js
Next.jsのRoute Groupの使い方を完全ガイド!App Routerでフォルダ構成を整理する方法
No.5
Java&Spring記事人気No5
Next.js
Next.js Pages Routerのメリット・デメリットを完全解説!初心者でも理解できるNext.jsルーティングの基本
No.6
Java&Spring記事人気No6
React
ReactのJSXはどうやって動く?Babelによるコンパイルの仕組みをやさしく解説
No.7
Java&Spring記事人気No7
React
Reactでキーボードイベントを活用する方法!onKeyDown, onKeyUp, onKeyPressを初心者向けに解説
No.8
Java&Spring記事人気No8
Next.js
Next.js Pages Routerでページごとのレイアウトを簡単に実現する方法!初心者向け完全ガイド