useContextはどういう時に使用するか
コンポーネントをまたいで値を渡す時。
propsで渡すと孫コンポーネントに渡す時に、一度、子や孫コンポーネントを経由しなければならなくなりバケツリレーになる。(propドリル)
さらにContextのいい点はContextで管理している状態や関数をそれぞれの子コンポーネントで共通して扱えるということ。
Contextの概念図
以下の図は、AuthContextという認証関連の変数や操作ロジックを扱ったContextと、それを実際に使用する2つのコンポーネントとの関係性を図示したもの。
・ログインしているかどうかを示す変数であるisAuthがAuthContextで一元的に管理されている
・この子コンポーネントはisAuthを使えるようになり、isAuthの値に応じた処理を書くことができるようになる
・コンポーネントAではloginHandlerを呼び出すことで、AuthContext内のisAuthをtrueに変更することができる
Contextの使い方
今回はこういうファイル構成にしてComponentAとComponentBでそれぞれ共通の変数を扱うようにする。
実際にはありえないがまぁ今回はよしとする。
├── App.jsx
├── AuthContext.jsx
├── ComponentA.jsx
└── ComponentB.jsx
Step 1.Contextの作成
まずは子コンポーネントで使う変数や関数を管理するためのContextを作成する。
ここではAuthContextを作成する。
ポイントは以下の2つ
①createContextでContextオブジェクトを作成し、外部で使えるようにexportする
②子コンポーネントをContextオブジェクトのProviderでラップすることでvalueに記載した変数や関数を子コンポーネントで使用できるようにする
import React, { useState, createContext } from 'react';
// Contextオブジェクトを作成し、exportする
export const AuthContext = createContext();
const AuthContextProvider = props => {
const [isAuth, setIsAuth] = useState(false);
const login = () => {
setIsAuth(true);
}
return (
// Providerで子コンポーネントをラップする
// valueに子コンポーネントで使いたい変数や関数を与える
<AuthContext.Provider value={{login, isAuth}}>
{props.children}
</AuthContext.Provider>
)
}
export default AuthContextProvider;
createContext は Contextオブジェクトを作り出していて、これによって Provider とConsumer ができる。
Provider は与える側、Consumer は受け取る側。
hooks ではConsumer は useContext で代用される。
Step 2.Providerを適切な位置に配置する
import { ComponentA } from "./ComponentA";
import { ComponentB } from "./ComponentB";
import AuthContextProvider from "./AuthContext";
function App() {
return (
<BrowserRouter>
<AuthContextProvider>
<Switch>
<Route path="/a" component={ComponentA} />
<Route path="/b" component={ComponentB} />
</Switch>
</AuthContextProvider>
</BrowserRouter>
);
}
export default App;
子コンポーネントであるComponentAとComponentBではStep1のAuthContextProviderで定義した変数と関数を使える準備ができたということになる。
Step 3.子コンポーネントでContextを使う
ComponentA
①useContextをimoprt
②useContextの引数にAuthContextで作成したContextオブジェクト(Step 1で作成)を入れる
③使いたいオブジェクトを取り出す(ここではisAuthとlogin)
import React, { useContext } from "react";
import { AuthContext } from "./AuthContext";
import { Link } from "react-router-dom";
const ComponentA = () => {
const { isAuth, login } = useContext(AuthContext);
return (
<div className="auth">
<h2>ComponentA</h2>
{isAuth ? (
<h2>認証されました</h2>
) : (
<>
<h2>認証されてません</h2>
<button onClick={login}>ログイン</button>
</>
)}
<Link to="/b">ComponentBへ</Link>
</div>
);
};
export default ComponentA;
ここではisAuthの真偽によって表示する内容を変えている。
さらにonClickイベントでログイン関数を呼び出している。
ComponentB
import React, { useContext } from "react";
import { AuthContext } from "./AuthContext";
const ComponentB = () => {
const { isAuth } = useContext(AuthContext);
return (
<div>
<h2>ComponentB</h2>
{isAuth ? <h2>認証されました</h2> : <h2>認証されてません</h2>}
<Link to="/a">ComponentAへ</Link>
</div>
);
};
export default ComponentB;
ComponentBも同様にisAuthを取り出して表示内容を変えている。
Contextによって何ができるようになったのか
①ComponentAでログインボタンを押すことでlogin関数が呼び出される
②AuthContextのisAuthがfalseからtrueに変更される
③ComponentA, ComponentBでそれぞれ変更されたisAuthの値を使えるようになった
つまりComponentAによる値の変更をComponentBで検知できるようになった。
参考サイト
[useContextの使い方]
(https://www.sunapro.com/usecontext/)