コンテクストフックは、コンポーネント間でデータ(props)を受け渡すための仕組みです。
Webサイトのテーマ(ダークモード/ライトモードなど)の切り替えや、ユーザー認証状態の監視などを実装する際に使います。
Contextを使えば、以下のようなアプリを実装できます。
useContextで作ったタスク管理アプリ
本記事で、useContextの基本的な使い方をマスターしておきましょう。
1.コンテクストとは
コンポーネント間でデータを共有する場合、通常はpropsが使われます。
親と子の間に中間コンポーネントが存在する場合(親→子→孫)でも、同様にpropsを使います。
これは、Reactの「単方向データフロー(親から子方向へのデータの受け渡し)」という設計上、正しいデータの流れです。
ただし、
- 多数のコンポーネントを経由して目的のコンポーネントにpropsを渡す
- 複数のコンポーネントで同じデータを使用する
という場合、propsを使ったデータの受け渡しは、コードの可読性や保守性が低くなります。

一方で、コンテクストフックを使用すれば、親コンポーネントから直接、目当てのコンポーネントにデータを受け渡せるようになります。

2.コンテクストフックの基本構文
コンテクストフックは、
- Contextを作成するための「createContext」
- Contextを使うための「useContext」
に分けられます。
2-1.createContext
createContextは、その名の通り、コンテクストを作成する関数です。
createContextの例
const DemoContext =createContext(Value)
2-1-1.createContextの返り値
createContextの返り値(以下の「DemoContext」に当たる要素)は、オブジェクトを返します。
const DemoContext =createContext(Value)
createContextの返り値であるオブジェクトは、以下のような、「プロバイダー(コンポーネントにコンテクストの値を渡すもの)」プロパティを持っています。
- 「SomeContext」:React19で使われているプロバイダー。
- 「SomeContext.Provider」 :React19以前のバージョンで使われていたプロバイダー。
- 「SomeContext.Consumer」:これも従来の記法。 あまり使用されていない。
使い方としては、親コンポーネントでcreateContextを宣言し、子コンポーネントをこの「プロバイダー」でラップすることで、子コンポーネントにデータを渡します。
const DemoContext =createContext(null);
functionParentComponent(){
return(
<DemoContext value="provided value">
<ChildComponent />
</DemoContext>
);
}
プロバイダーのprops「value」
valueに渡した値は、プロバイダーの内側にあるすべての子孫コンポーネントで読み取れます。
valueには、文字列や数値はもちろん、配列・オブジェクト・関数などの型のデータも渡せます。
なお、valueを指定しない、あるいは違う名前のpropsを渡すと、コンテクストは「undefined」を返します。
プロバイダーをネストしている場合の挙動
同じコンテクストをネストした場合、フックの挙動に注意が必要です。
ほぼ使わないケースですが、値をオーバーライドしたい時に使う記法です。
以下のように、呼び出し側のコンポーネントは、一番近いロバイダーのvalueの値を受け取ります。
<DemoContext value="outer">
<DemoContext value="inner">
<Child /> //useContext(DemoContext)は「inner」
</DemoContext>
</DemoContext>
2-1-2.createContextの引数
createContextの引数(以下の「default」に当たる要素)は、コンポーネントがコンテクストを読み込んだ際、プロバイダーが存在しない場合に、コンテクストが返す値です。
実際の開発では、ほぼ「null」値が指定されます。
const DemoContext =createContext(default)
なお、createContextの引数で指定するデフォルト値は、useContext(後で解説します)がプロバイダーを見つけられない場合にのみ使用します。
createContextの引数は、静的な値であり動的に変化しないので注意が必要です。
コンテクストの値を動的に変更したい場合は、コンテクストフックをstate(状態)と組み合わせて使用する必要があります。
2-2.useContext
useContextは、その名の通り、コンテクストを使うための関数です。
正確には、値の読み取りとサブスクライブ(値の変更を監視して、読み取り側のコンポーネントを再レンダーする)を行います。
useContextの例
const demo =useContext(demoContext)
2-2-1.useContextの返り値
useContextの返り値(以下の「demo」に当たる要素)には、事前にcreateContextで作成したコンテクストの現在の値が入っています。
const demo =useContext(demoContext)
「2-1-1.createContextの返り値」で解説した通り、同じコンテクストをネストする形でラップしている場合は、一番近いコンテクストに渡されたvalueが返り値に入ります。
また、対応するコンテクストにプロバイダーが存在しない場合は、 createContextの引数を返します。
なお、useContextの返り値が返す値は、静的な値だけではありません。
useContextは、コンテクストの変更を監視し、変化があれば、useContextを使っているコンポーネントを再レンダーします。
2-2-2.useContextの引数
useContextの引数(以下の「demoContex」に当たる要素)には、createContextで作ったコンテクストを渡します。
const demo =useContext(demoContext)
3.コンテクストフックの使用法(静的な値)
まずは、静的な値を受け渡すコードで、コンテクストの基本的な使い方を理解しましょう。
完成版のコード
step1.コンテキストを定義するファイルを作る
まずは、コンテキストを定義したファイル「HogeContext.js」を作ります。
最初に、createContextをインポートしましょう。
HogeContext.js
import{ createContext }from'react';
次に、createContextを呼び出して、HogeContextを定義します。
HogeContext.js
exportconst HogeContext =createContext("default value");
//"default value"はプロバイダーがない場合に返される値。
step2.プロバイダーを渡すファイルを作る
「HogeContext.js」を作成したあとは、プロバイダーを使って値を渡す側のファイル「App.jsx」を作ります。
最初に、先ほど作った「HogeContext」をインポートしましょう。
App.jsx
import{ HogeContext }from"./HogeContext";
次に、空の関数コンポーネントを定義しておきましょう。
App.jsx
constApp=()=>{
return(
<>
</>
);
}
エクスポートもしておきましょう。
App.jsx
exportdefault App;
step3.コンテキストの値を受け取るファイルを作る
「App.jsx」を作成したあとは、プロバイダーを使って値を渡す側のファイル「Child.jsx」を作ります。
まずは、値を受け取るための「useContext」をインポートしましょう。
Child.jsx
import{ useContext }from"react";
次に、「App.jsx」でも読み込んだ「HogeContext」をChild.jsxにもインポートします。
Child.jsx
import{ HogeContext }from"./HogeContext";
空の関数コンポーネントも定義し、エクスポートしておきましょう。
Child.jsx
constChild=()=>{
return(
<>
</>
);
}
exportdefault Child;
step4.親コンポーネントで子コンポーネントを読み込んでプロバイダーでラップする
コンテキストを扱うための3つのファイルを用意できたら、次はApp.jsxに子コンポーネント(Child.jsx)をインポートしましょう。
App.jsx
import Child from"./Child";
また、プロバイダーは、値を渡したいコンポーネントをラップする必要があります。
プロバイダーの内側にあるコンポーネントだけがuseContextで値を受け取れます。
そのため、インポートした子コンポーネントを、プロバイダーでラップします。
加えて、valueに「context value」という文字列を渡しておきましょう。
App.jsx
constApp=()=>{
return(
<HogeContext value="context value">
<Child />
</HogeContext>
);
}
step5.子コンポーネントで値を受け取る
最後に、コンテキストを使う側のコンポーネント(Child.jsx)で、値を受け取ります。
まずは、Child.jsxでuseContextを呼び出します。
Child.jsx
constChild=()=>{
const hoge =useContext(HogeContext);
return(
<>
</>
);
}
次に、useContextで受け取った値を表示してみましょう。
Child.jsx
constChild=()=>{
const hoge =useContext(HogeContext);
return(
<p>
{hoge}
</p>
);
}
問題なくコンテキストを受け取れていれば、画面には「context value」と表示されているはずです。
もし、コンテキストを受け取れていなければ、画面に「default value」と表示されます。
プロバイダーのラップや、valueの設定が間違っていないか確認しましょう。
4.コンテクストフックの使用法(動的な値)
ほとんどの場合、コンテクストでは、動的な値を扱います。
動的な値を扱うためには、コンテクストフックとstateの併用が必要です。
ここでは、先ほど「3.Contextフックの使用法(静的な値)」で解説したコードを使って、コンテクストで動的な値を扱う方法を解説します。
複雑な修正は必要なく、「3.Contextフックの使用法(静的な値)」で解説したコードの「App.jsx 」を修正するだけで、動的な値を受け渡せます。
デモアプリ
完成版のコード
step1.useStateをインポートする
まずは、App.jsxにstateフックをインポートしましょう。
App.jsx
import{ useState }from"react";
step2.useStateを呼び出す
次に、useStateを呼び出して、プロバイダーに渡すstateを作ります。
App.jsx
constApp=()=>{
const[hoge, setHoge]=useState("initial value");
return(
<HogeContext value="context value">
<Child />
</HogeContext>
);
}
step3.valueにstateを渡す
最後に、プロバイダーのvalueに stateを渡します。
App.jsx
constApp=()=>{
const[hoge, setHoge]=useState("initial value");
return(
<HogeContext value={hoge}>
<Child />
<button onClick={()=>setHoge("updated value")}>
値を更新する
</button>
</HogeContext>
);
};
これで、ボタンをクリックすると、
- ボタンをクリックする(画面表示は「initial value」)
- setHogeが呼ばれる
- Appが再レンダーされる
- valueが更新される
- Childが再レンダーされる
- useContextが新しい値を受け取る
- 画面が書き換わる(画面表示は「updated value」)
という流れで、コンテキストの値が動的に書き換えられるようになりました。
5.注意点
5-1.useContextの呼び出し位置
同じコンポーネント内で、useContextとcreateContextを呼び出すと、プロバイダーは、valueの値ではなく、createContextの引数を返します。
createContextで作ったプロバイダーは、useContexを使っているコンポーネントの上に配置する必要があります。
5-2.createContextが複数回呼ばれる場合の挙動
reateContextの返り値は、オブジェクトです。
ReactはこのオブジェクトをキーとしてプロバイダーとuseContextを紐づけています。
そのため、プロバイダーとuseContextが同じオブジェクト(内部的には===に比較で一致判定をしています。)を使っていないと、コンテクストは正常に動きません。
モジュールが何らかの理由で複製され、同じファイルが2回読み込まれると、createContextが複数回実行され、異なるコンテクストオブジェクトが生成されます。
そうした場合、プロバイダーとuseContextが別のオブジェクトを参照し、プロバイダーが見つからず、createContextの引数を返すため、意図しない動作を引き起こす可能性があります。
また、ビルドツールの問題によって、同じモジュールが複数コピーされてしまう場合も、プロバイダーとuseContextが異なる参照を持つことになり、コンテクストが正常に動作しないケースがあります。
5-3.memoによる再レンダーの防止
プロバイダーのvalueが変わると、useContextを使っているコンポーネントは、必ず再レンダーされます。
Reactのmemoでラップしたコンポーネントは、propsが前回と同じ値なら再レンダーをスキップできます。
しかし、この再レンダーは、memoを使っても止められません。
参考:https://ja.react.dev/reference/react/memo
6.あとがき
コンテクストは、Reactアプリ全体で共有したい値を、どのコンポーネントからでも取り出せるようにするためのフックです。
Webアプリ開発では、テーマ設定や認証情報など、複数の画面で共通のデータを扱う場合があります。
コンテクストは、こうした「グローバルに扱いたい状態」を簡単に共有できます。
今回は、コンテクストの基本的な考え方や仕組み、注意点まで解説しました。
ReactでWebアプリ開発するうえで欠かせないフックなので、使い方をしっかりマスターしておきましょう。



