useContextとは
React Hooksの一つで、グローバルにデータを管理することができる仕組みです。
通常親コンポーネントから子コンポーネントにデータを渡す際はpropsを介して行うかと思います。
しかし親から子、そのまた子といったように複数のコンポーネントを介してデータを渡す場合にpropsでのバケツリレーのようなやり方では設定が複雑になってきます。
useContextを使用することでpropsを利用することなく異なる階層のコンポーネントとデータの共有を行うことができます。
グローバルに「データ」を管理することができるもの。
「props」によるバケツリレーを防ぐために利用する。
シンプルなコード例
下記のようなディレクトリ構造でuseContextを使用してみます。
├ Example.js
├ components/
├ Child.js
├ GrandChild.js
import Child from "./components/Child";
import { createContext } from "react";
export const MyContext = createContext("useContextのテスト");
const Example = () => {
return <Child />;
};
export default Example;
import GrandChild from "./GrandChild";
const Child = () => (
<div style={{ border: "1px solid black", padding: 10 }}>
<h3>子コンポーネント</h3>
<GrandChild />
</div>
);
export default Child;
import { useContext } from "react";
import { MyContext } from "../Example";
const GrandChild = () => {
const value = useContext(MyContext);
return (
<div style={{ border: "1px solid black" }}>
<h3>孫コンポーネント</h3>
{value}
</div>
);
};
export default GrandChild;
上記関数コンポーネントを実行していただくと下記のようにpropsを使用することなく、孫コンポーネントにデータを渡せていることがわかるかと思います。

コード解説
useContextを使用するには、reactからcreateContext()を読み込む必要があります。
import { createContext } from "react";
そのcreateContext()を使用し、コンテキストを定義し、exportします。
createContext()の引数にはpropsを通さずに渡したい値を記述します。
export const MyContext = createContext("useContextのテスト");
そしてGrandChildコンポーネントで使用したいので、importしています。
ここでuseContext()をreactから読み込みます。
import { useContext } from "react";
import { MyContext } from "../Example";
最後にuseContext()の引数にimportしたMyContextを渡すことで、設定しておいた値を取得することができます。
const value = useContext(MyContext);
// value = useContextのテスト
stateとuseContextを組み合わせて使う方法
次にネスト構造になっていない、コンポーネント間でクリックを検知して、stateを変更する方法について解説します。
下記のような構造で作成します。
├ Example.js
├ components/
├ Child.js
├ GrandChild.js
├ Other.js
Otherコンポーネントの兄弟に、Childコンポーネントがあり、そのChildコンポーネントの中にはGrandChildコンポーネントがあるような構造です。
Otherコンポーネントのクリックを検知し、GrandChirdにあるstateを変更させます。
import { createContext, useState } from "react";
import Child from "./components/Child";
import OtherChild from "./components/OtherChild";
export const MyContext = createContext();
const Example = () => {
const [value, setValue] = useState(0);
return (
<MyContext.Provider value={[value, setValue]}>
<Child />
<OtherChild />
</MyContext.Provider>
);
};
export default Example;
import { useContext } from "react";
import { MyContext } from "../Example";
const OtherChild = () => {
const [, setValue] = useContext(MyContext);
const clickHandler = (e) => {
setValue((prev) => prev + 1);
};
return (
<div>
<h3>他の子コンポーネント</h3>
<button onClick={clickHandler}>+</button>
</div>
);
};
export default OtherChild;
import GrandChild from "./GrandChild";
const Child = () => (
<div style={{ border: "1px solid black", padding: 10 }}>
<h3>子コンポーネント</h3>
<GrandChild />
</div>
);
export default Child;
import { useContext } from "react";
import { MyContext } from "../Example";
const GrandChild = () => {
const [value] = useContext(MyContext);
return (
<div style={{ border: "1px solid black" }}>
<h3>孫コンポーネント</h3>
{value}
</div>
);
};
export default GrandChild;
上記コンポーネントを実行すると、下記のように他のコンポーネントで作成したボタンをクリックすると、孫コンポーネントにあるstate(カウント)が変化するようになります。
コード解説
まず、stateを使用するコンポーネントを全て読み込んでいる場所でuseStateやcontextを定義します。
import { createContext, useState } from "react";
import Child from "./components/Child";
import OtherChild from "./components/OtherChild";
export const MyContext = createContext(); // context定義
const Example = () => {
const [value, setValue] = useState(0); // state定義
...
};
定義したcontext(MyContext)のProviderというコンポーネントでstateを使用するコンポーネントを包装します。
そのProviderコンポーネントのvalueを設定することで、valueにセットされた値がuseContextを通してネストされたコンポーネントで取得することができるようになります。
今回はvalueに設定する値は定義しておいた、stateとその変更関数ごと、配列のまま渡します。
<MyContext.Provider value={[value, setValue]}>
<Child />
<OtherChild />
</MyContext.Provider>
useContextの挙動とすると順々に親のコンポーネントを参照していき、Providerコンポーネントのvalueに設定された値を取得します。
Providerコンポーネントのvalueを設定しなかった場合、createContext()時に渡された引数を取得します。
例)
export const MyContext = createContext('これが初期の値になるよ');
ボタンが作成されているOther.jsではcontextをimportし、useContext()の引数に渡します。
import { useContext } from "react";
import { MyContext } from "../Example"; // 定義したMyContextのimport
それをuseContext()の引数に渡し、返り値を格納することでvalueに設定された値を取得できます。
valueには[value, setValue]の配列を渡してありますが、このコンポーネントではstateは使いませんので、分割代入で1番目の要素であるsetValue、つまりstateの変更関数だけを取得します。
const [, setValue] = useContext(MyContext); // 使用する変更関数のみ取得
そしてボタンのonClickイベントでclickHandlerを実行させます。
clickHandler()はsetValueでstateの値に+1をする関数です。
const clickHandler = (e) => {
setValue((prev) => prev + 1);
};
stateを表示しているGrandChild.jsも同じ要領で、useContext()の引数にcontext、つまりvalueに設定したstateの値のみ取得して表示させているという流れです。
import { useContext } from "react";
import { MyContext } from "../Example"; // contextのimport
const GrandChild = () => {
const [value] = useContext(MyContext); // 分割代入でstateのみ取得
return (
<div style={{ border: "1px solid black" }}>
<h3>孫コンポーネント</h3>
{value}
</div>
);
};
export default GrandChild;
