Context

React のコンテキストは、propsを使わずに子コンポーネントに親のデータを渡す為に使います。これにより

  • 複数のコンポーネントから成り立つコンポーネント間のpropsが簡単になる
  • 子が特定の親の下に置かれてるどうか確認できる

などの利点があります。

コンテキストを作るにはReact.createContextを使います。これはデフォルトで渡されることになる値を引数として1つ受け取ります。

const Meta = React.createContext({title: 'blog title'});

このMetaはオブジェクトでProviderConsumer2つのコンポーネントを持っています。
まずProviderは渡すデータを置くために使います。データはこの要素のvalue属性に渡します。   次にConsumerは渡ってきた値を受け取る為の要素です。
Consumerは上位階層にProviderがある時、一番近いそれに渡された値を受け取りますが、もしProviderが1つも無い場合、コンテキストを作る時に渡したデフォルト値を受け取ります。注意なのがこのコンポーネントのchildrenはデータを引数に受け取る関数だという点です。

です。この例はProviderと通す時と通さない時の動作を見れるもので、それぞれpropsで何も値を渡していないのにapp titleblog titleと別の内容が表示されます。

const Meta = React.createContext({ title: "blog title" });

const Title = () => {
  return (
    <Meta.Consumer>
      {meta => {
        return <h1>{meta.title}</h1>;
      }}
    </Meta.Consumer>
  );
};

const App = () => {
  return (
    <>
      <Title />
      <Meta.Provider value={{ title: "app title" }}>
        <Title />
      </Meta.Provider>
    </>
  );
}

useContext

Consumerの代わりに、useContextフックを使う方法もあります。このフックを使って上記のコードを書き換えるとこうなります。

const Meta = React.createContext({ title: "blog title" });

const Title = () => {
  const meta = React.useContext(Meta);

  return <h1>{meta.title}</h1>;
};

export default function App() {
  return (
    <>
      <Title />
      <Meta.Provider value={{ title: "app title" }}>
        <Title />
      </Meta.Provider>
    </>
  );
}

useContextへはConsumerを渡すわけではなくコンテキストそのものを渡します。