7
8

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

【React】グローバルなState管理をする React.createContext Context.Provider

Posted at

はじめに

Reactでコンポーネントが多くなると、Propsを使って値の受け渡しが多くなり、ルートのコンポーネントから最下層のコンポーネントへPropsのバケツリレーのようになることがあります。
そこでReact.createContextを使うと、グルーバルなState管理ができるようになり、コードがスッキリし、複雑化するのを防ぐことができるようになります。
React.createContextの使い方をモダンJavaScriptの基本から始める React実践の教科書で勉強したことを参考にまとめていきます。

1.React.createContextでContextの器を作る

はじめにcomponentの下にprovidersというフォルダを作成し、グローバルなState管理をするためのファイルを作成します。ここでは、AdminFlagProvider.jsxを作成しました。

react-basic/src/components/providers/AdminFlagProvider.jsx
import { createContext } from "react";

export const AdminFlagContext = createContext({});

2.作成したContextのProviderでグローバルStateを扱いたいコンポーネントを囲う

Providerのコンポーネントは、何でも囲めるようにPropsとしてchildrenを受け取るようにするのがポイントです。
上記で用意したAdminFlagContextには、Providerが用意されているので、それを返却するようにします。

react-basic/src/components/providers/AdminFlagProvider.jsx
import { createContext } from "react";

export const AdminFlagContext = createContext({});

export const AdminFlagProvider = (props) => {
  // 何でも囲めるようにPropsとしてchildrenを受け取るようにする。
  const { children } = props;

  const sampleobj = { sampleValue: "テスト" };

  return (
    // AdminFlagContextには、Providerが用意されているのを返却する。
    // valueの中にグローバルに扱う実際の値を設定する
    <AdminFlagContext.Provider value={sampleobj}>
      {children}
    </AdminFlagContext.Provider>
  );
};

3.Providerを使いたい範囲のコンポーネントを囲う

今回は、アプリ全体で参照できるようにするために、index.jsの中でAppコンポーネントを囲みます。

/react-basic/src/index.js
import ReactDom from "react-dom";
import { App } from "./App";
import "./index.css";
import { AdminFlagProvider } from "./components/providers/AdminFlagProvider";

ReactDom.render(
  <AdminFlagProvider>
    <App />
  </AdminFlagProvider>,
  document.getElementById("root")
);

4.Stateを参照したいコンポーネントでReact.useContextを使う

React.useContextを使い、その引数に対象のContextを指定するだけで参照することができます。下記のコードを実行することで、AdminFlagProvider.jsxで定義したsampleobjの値を習得することができます。

react-basic/src/components/EditButton.jsx
import { useContext } from "react";

import { AdminFlagContext } from "./providers/AdminFlagProvider";

export const EditButton = (props) => {
  const AdminFlagValue = useContext(AdminFlagContext);
  const { isAdmin } = props;

// useContextで用意したsampleobjの値を取得することができた
  console.log(AdminFlagValue);

  return <button disabled={!isAdmin}>編集</button>;
};

/react-basic/src/App.jsx
import { useState } from "react";
import { Card } from "./components/Card";

export const App = () => {
  const [isAdmin, setIsAdmin] = useState(false);
  const onClickSwitch = () => setIsAdmin(!isAdmin);

  return (
    <div>
      {isAdmin ? <span>管理者です</span> : <span>管理者以外です</span>}
      <br />
      <button onClick={onClickSwitch}>切り替えボタン</button>
      <Card isAdmin={isAdmin} />
    </div>
  );
};
/react-basic/src/components/Card.jsx
import { EditButton } from "./EditButton";

export const Card = (props) => {
  const { isAdmin } = props;

  return (
    <div>
      {/* propsをそのまま受け渡ししている、バケツリレーを行っている */}
      <EditButton isAdmin={isAdmin} />
    </div>
  );
};

次のステップ!Contextの更新と参照処理を行う

ContextのStateの更新と参照には、Providerを記載しているファイルににStateを定義し、そのStateの値と更新関数をContextのvalueに設定します。

/react-basic/src/components/providers/AdminFlagProvider.jsx
import { createContext, useState } from "react";

export const AdminFlagContext = createContext({});

export const AdminFlagProvider = (props) => {
  const { children } = props;

// Contextの更新と参照するためにStateを定義する
  const [isAdmin, setIsAdmin] = useState(false);

  // ContextオブジェクトとしてisAdminとsetIsAdminを設定(オブジェクトの省略記法)
  return (
    <AdminFlagContext.Provider value={{ isAdmin, setIsAdmin }}>
      {children}
    </AdminFlagContext.Provider>
  );
};

useContextを使って、グローバルなStateの値を取得することができるようになりました。
さらに、propsで値を受け渡していた箇所を削除することができ、スッキリさせることができます。

react-basic/src/components/EditButton.jsx
import { useContext } from "react";

import { AdminFlagContext } from "./providers/AdminFlagProvider";

// 不要なpropsを削除できた
export const EditButton = () => {

  //useContextを使って、グローバルなStateの値を取得する
  const { isAdmin } = useContext(AdminFlagContext);

  return <button disabled={!isAdmin}>編集</button>;
};

/react-basic/src/components/Card.jsx
import { EditButton } from "./EditButton";

// 不要なpropsを削除でき、シンプルになりました。
export const Card = () => {
  return (
    <div>
      <EditButton />
    </div>
  );
};
/react-basic/src/App.jsx
import { useContext } from "react";
import { Card } from "./components/Card";
import { AdminFlagContext } from "./components/providers/AdminFlagProvider";

export const App = () => {
// useContextから更新するための、Stateを取得を行う。
  const { isAdmin, setIsAdmin } = useContext(AdminFlagContext);

//グローバルなStateの値を更新!
  const onClickSwitch = () => setIsAdmin(!isAdmin);

  return (
    <div>
      {isAdmin ? <span>管理者です</span> : <span>管理者以外です</span>}
      <br />
      <button onClick={onClickSwitch}>切り替えボタン</button>
      <Card isAdmin={isAdmin} />
    </div>
  );
};
7
8
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
8

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?