Contextで状態管理

2 min read読了の目安(約2200字

はじめに

React初心者です。
ReactのContextで状態管理をする方法について学習したのでまとめてみました。

普通に書くと...?

とにかく props 経由でバケツリレーをしていることが伝わればと思います。
実際に使うのは最下層のChildComponentなのに、経由するコンポーネント全てに props を渡してあげないといけません。

export const RootComponent = () => {
  const theme = "hoge";
  return (
    <div>
      <h1>ルートコンポーネント</h1>
      <ParentComponent theme={theme} />
    </div>
  );
};

export const ParentComponent = (props) => {
  return (
    <div>
      <h1>親コンポーネント</h1>
      <ChildComponent theme={props.theme} />
    </div>
  );
};

export const ChildComponent = (props) => {
  return (
    <div>
      <h1>子コンポーネント</h1>
      <p>{props.theme}</p>
    </div>
  );
};

Context を使うと...?

Context を使えば、中間の要素群を経由しなくても、離れた要素へプロパティを渡すことができます。

import { createContext, useContext } from "react";

const ThemeContext = createContext({});

export const ThemeProvider = (props) => {
  const { children } = props;
  const contextTheme = "hoge";

  return (
    <ThemeContext.Provider value={{ contextTheme }}>
      {children}
    </ThemeContext.Provider>
  );
};

export const RootComponent = () => {
  return (
    <ThemeProvider>
      <h1>ルートコンポーネント</h1>
      <ParentComponent />
    </ThemeProvider>
  );
};

export const ParentComponent = () => {
  return (
    <div>
      <h1>親コンポーネント</h1>
      <ChildComponent />
    </div>
  );
};

export const ChildComponent = () => {
  const theme = useContext(ThemeContext);

  return (
    <div>
      <h1>子コンポーネント</h1>
      {theme.contextTheme} //"hoge"と表示される
    </div>
  );
};

createContext

createContextによってコンテキストオブジェクトを作成します。

const ThemeContext = createContext({});

Provider

値を渡したい要素をProviderコンポーネントで挟みます。
以下の例であれば、contextThemeが子コンポーネントに渡されています。

export const UserProvider = (props) => {
  const contextTheme = "hoge";

  return (
    <ThemeContext.Provider value={{ contextTheme }}>
      // 子コンポーネントたち
    </ThemeContext.Provider>
  );
};

useContext

useContextを使うことでコンテクストの現在値を取得できます。
今回の例では、ThemeContextを取得し、その中のcontextThemeを表示しています。

export const ChildComponent = () => {
  const theme = useContext(ThemeContext);

  return (
    <div>
      <h1>子コンポーネント</h1>
      {theme.contextTheme}
    </div>
  );
};