useContext
useContext()
とは、ツリー内の様々な階層からContext
に収容されているデータへアクセスすることができます。useContext()
を利用することで親コンポーネントから子コンポーネント、子コンポーネントから孫コンポーネントへprpos
で値を渡さなくても、直接親コンポーネントから孫コンポーネントへ値を渡すことができます。
useContextを利用するために必要なコンポーネント
Context
機能を利用するためには以下のコンポーネントが必要になります。
オブジェクト/コンポーネント | 説明 |
---|---|
Contextオブジェクト | React.createContext()の戻り値 |
Providerコンポーネント | Contextオブジェクトが保持しているコンポーネント |
Consumerコンポーネント | useContext()を利用することで、Contextオブジェクトから値を取得できるコンポーネント |
useContextを使用したサンプル1
createContext()を利用してProvider
コンポーネントであるSampleProvider
コンポーネントとContext
オブジェクトであるSampleObject
を作成します。
index.js
index.js
import { StrictMode } from "react";
import { createRoot } from "react-dom/client";
import App from "./App";
const rootElement = document.getElementById("root");
const root = createRoot(rootElement);
root.render(
<StrictMode>
<App />
</StrictMode>
);
SampleProvider.js
SampleProvider.js
// 関数コンポーネント内でceateContextを扱えるようにするためimportする
import React, { createContext } from "react";
// createContext()を利用して、ContextオブジェクトSampleObjectを作成
// 他のファイルでSampleObjectを参照できるようexportする
export const SampleObject = createContext();
// 子コンポーネント(下階層)に渡すtextを定義する
const text = "これはProviderから渡された値";
// 定義したtextの情報を保持するSampleObjcet.Providerを作成する
// SampleObject.Providerでprops.childrenをラップしておくと
// ラップしたコンポーネントのツリー内でContextオブジェクトを
// 参照できるようなるchildrenをpropsで受け取る
export const SampleProvider = (props) => {
return (
// 共有したい値をvalue属性の値として渡す
// value属性の値は、SampleProviderコンポーネントでラップした
// コンポーネントのツリー内で参照できるようになる
<SampleObject.Provider value={text}>{props.children}</SampleObject.Provider>
);
};
App.js
App.js
// SampleProviderコンポーネントをインポートする
import { SampleProvider } from "./SampleProvider";
// Firstコンポーネントをインポートする
import { First } from "./First";
export default function App() {
return (
<>
// SampleProviderでラップしているので、ラップされたFirstコンポーネントの配下で
// Contextオブジェクトを参照できるようになる
// Firstコンポーネント配下のコンポーネント(Second、Third)は、Provider内なので、
// value属性の参照できる
<SampleProvider>
<First />
</SampleProvider>
</>
);
}
今回、Contextオブジェクトを保持しているProviderコンポーネンをSampleProviderコンポーネントとして別ファイルに記述していましたが、以下のようにApp.jsに一つにまとめて書くことができます。
App.js
// 関数コンポーネント内でceateContextを扱えるようにするためimportする
import React, { createContext } from "react";
// createContext()を利用して、ContextオブジェクトSampleObjectを作成
// 他のファイルでSampleObjectを参照できるようexportする
export const SampleObject = createContext();
// 子コンポーネント(下階層)に渡すtextを定義する
const text = "これはProviderから渡された値";
// Firstコンポーネントをインポートする
import { First } from "./First";
export default function App() {
return (
<>
// SampleObject.Providerでラップするとラップすると、
// ラップされたコンポーネントのツリー内(First、Second、Third)de
// value属性の値を参照できるようになる
<SampleObject.Provider value={text}>
// Firstコンポーネントは、Provider内なので、value属性の値を参照できる
<First />
</SampleObject.Provider>
</>
);
}
First.js
First.js
// Secondコンポーネントをインポート
import { Second } from "./Second";
// 他のファイルでFirstコンポーネントを使用できるようexportする
export const First = () => {
return (
<>
<p>Firstコンポーネント</p>
<Second />
</>
);
};
Second.js
Second.js
// Thirdコンポーネントをインポート
import { Third } from "./Third";
// 他のファイルでSecondコンポーネントを使用できるようexportする
export const Second = () => {
return (
<>
<p>Secondコンポーネント</p>
<Third />
</>
);
};
Third.js
Third.js
// 関数コンポーネント内でuseContextを使用できるようインポートする
import React, { useContext } from "react";
// ContextオブジェクトのSampleObjectをインポートする
import { SampleObject } from "./SampleProvider";
// 他のファイルでThirdコンポーネントを使用できるようexportする
// Thirdコンポーネントは、Contextオブジェクトから値を取得できるConsumerコンポーネント
export const Third = () => {
// useContext()を使用して、Contextオブジェクトから値を取得
const sampleText = useContext(SampleObject);
return (
<>
<p>
// sampleTextはProviderコンポーネントから取得したvalueの値
Thirdコンポーネント: <b>{sampleText}</b>
</p>
</>
);
};
useContextを使用したサンプル2
Provider
コンポーネントからuseState()
を使用して保持している値count
を受け取ります。
index.js
index.js
import { StrictMode } from "react";
import { createRoot } from "react-dom/client";
import App from "./App";
const rootElement = document.getElementById("root");
const root = createRoot(rootElement);
root.render(
<StrictMode>
<App />
</StrictMode>
);
CountProvider
CountProvider.js
// useState、createContextを使用できるようにインポートする
import React, { useState, createContext } from "react";
// 他のファイルでCountObjectを使用できるようにするためにexportする
// createContext()を使用して、ContextオブジェクトCountObjectを作成
export const CountObject = createContext();
// useStateで定義したcount/setCount情報を保持する
// CountObject.Providerを作成し、props.childrenをラップしておくと、
// CountProviderコンポーネントでラップしたコンポーネントのツリー内で
// Contextオブジェクトを参照できるようになる
// 今回の場合、propsで受け取る値はFirstコンポーネント
export const CountProvider = (props) => {
// 状態変数count、countを更新する関数setCountを定義する
const [count, setCount] = useState(0);
return (
// value属性の値は、CountProviderコンポーネントでラップした
// コンポーネントのツリー内(First、Second、Third)で参照できるようになる
<CountObject.Provider value={[count, setCount]}>
{props.children}
</CountObject.Provider>
);
};
App.js
App.js
// CountProviderコンポーネントをインポートする
import {CountProvider} from "./CountProvider";
// Firstコンポーネントをインポートする
import {First} from "./First";
export default function App() {
return (
<>
// CountProviderでラップしているので、ラップされたFisrtコンポーネントの配下で、
// Contextオブジェクトの値を参照できるようになる
// Firstコンポーネント配下のコンポーネントは、Provider内なので、value属性の値を参照できる
<CountProvider>
<First />
</CountProvider>
</>
);
}
First.js
First.js
// Secondコンポーネントをインポート
import { Second } from "./Second";
// 他のファイルでFirstコンポーネントを使用できるようexportする
export const First = () => {
return (
<>
<p>Firstコンポーネント</p>
<Second />
</>
);
};
Second.js
Second.js
// Thirdコンポーネントをインポート
import { Third } from "./Third";
// 他のファイルでSecondコンポーネントを使用できるようexportする
export const Second = () => {
return (
<>
<p>Secondコンポーネント</p>
<Third />
</>
);
};
Third.js
Third.js
// useContextを使用できるようインポートする
import React, { useContext } from "react";
// ContextオブジェクトのCountObjectをインポートする
import { CountObject } from "./CountProvider";
// 他のファイルでThirdコンポーネントを利用できるようにするためにexport
// Thirdコンポーネントは、Contextオブジェクトから値を取得できるConsumerコンポーネント
export const Third = () => {
// useContext()を使用してContextオブジェクトから値を取得
// [count, setCount]はProviderコンポーネントから取得したvalueの値
const [count, setCount] = useContext(CountObject);
// カウントアップする関数countIncrement
const countIncrement = () => {
setCount((prevCount) => prevCount + 1);
};
// カウントダウンする関数countDecrement
const countDecrement = () => {
setCount((prevCount) => prevCount - 1);
};
// カウントリセットする関数countReset
const countReset = () => {
setCount(0);
};
return (
<>
<p>
Thirdコンポーネント:<b>現在のカウント: {count}</b>
</p>
<button onClick={countIncrement}>+1ボタン</button>
<button onClick={countDecrement}>-1ボタン</button>
<button onClick={countReset}>リセットボタン</button>
</>
);
};