useContextを使うべく、公式追っていく。

今回はuseContextを見ていきます。
公式の[reference](https://ja.react.dev/reference/react/useContext#usage)でもいいのですが、今回は[コンテクストで深くデータを受け渡す](https://ja.react.dev/learn/passing-data-deeply-with-context)を見ていこうと思います。
(公式を追いながら、感じたことを含めてアウトプットしています。コードは飛び飛びですのであしからず...。)

----

> 通常、親コンポーネントから子コンポーネントには props を使って情報を渡します。しかし、props を多数の中間コンポーネントを経由して渡さないといけない場合や、アプリ内の多くのコンポーネントが同じ情報を必要とする場合、props の受け渡しは冗長で不便なものとなり得ます。コンテクスト (Context) を使用することで、親コンポーネントから props を明示的に渡さずとも、それ以下のツリー内の任意のコンポーネントが情報を受け取れるようにできます。

いわゆるバケツリレーで渡していくのは冗長ですよね。
渡したいコンポーネントに辿り着くまでに、経由するcomponent全てが情報知っている状態にもなります。

コンテクスト内では共通して使えるようにしておく、と言うことですね。

> もし props を受け渡すことなしに、データを必要としているツリー内のコンポーネントに直接データを「テレポート」させる方法があれば、素晴らしいと思いませんか？ React のコンテクスト機能を使えば、それが可能です！

えっ！？propsを使わずにコンポーネントにデータを!?
できらぁ！

## 例を見る

level を props としてそれぞれの <Heading> に個別に渡しています。

```jsx
// 公式から引用
<Section>
  <Heading level={3}>About</Heading>
  <Heading level={3}>Photos</Heading>
  <Heading level={3}>Videos</Heading>
</Section>
```

下記のようにして、Headingを操作できればスッキリしそうです。

```jsx
<Section level={3}>
  <Heading>About</Heading>
  <Heading>Photos</Heading>
  <Heading>Videos</Heading>
</Section>
```

> <Heading> コンポーネントは、最も近い `<Section>` のレベルをどうやって知ることができるのでしょうか？ これには、ツリー上部のどこかにあるデータを子コンポーネントが「要求する」方法が必要です。

Headingはなんとかして、Sectionの値を知りたいです。(Headinigに値をテレポートさせたい)
そんな時に`コンテクスト` が登場します。

### ステップ 1：コンテクストを作成する


>まずはコンテクストを作成する必要があります。複数のコンポーネントから使うことができるように、ファイルを作ってコンテクストをエクスポートする必要があります。

なるほど、では指定してみます。

```jsx
// 公式から引用
// LevelContext.js
import { createContext } from 'react';
export const LevelContext = createContext(1);
```

createContextに渡した `1` というのがテレポートさせる値です。
(この時点ではまだuseContextは登場しません。)

> createContext の唯一の引数はデフォルト値です。ここでは、1 という値は最大の見出しに対応するレベルを示していますが、任意の型の値（オブジェクトでも）を渡すことができます。デフォルト値の意味は次のステップで分かります。

createContextの引数(default値)に1を渡しましたが、何でも渡せそうです。

### ステップ 2：コンテクストを使用する 

> この例はまだちゃんと動作していません。すべての見出しが同じサイズになってしまっているのは、コンテクストの使用はしているが、まだコンテクストの提供を行っていないからです。React はどこから値を取得すればいいのか分かりません！

現在、createContextに初期値として入れた1を呼び出せてはいますが、、

```jsx
// 公式から引用
import { useContext } from 'react';
import { LevelContext } from './LevelContext.js';

export default function Heading({ children }) {
  const level = useContext(LevelContext); // 絶対1になる
  switch (level) {
    case 1:
      return <h1>{children}{level}</h1>;
    case 2:
      return <h2>{children}{level}</h2>;
    case 3:
      return <h3>{children}{level}</h3>;
    case 4:
      return <h4>{children}{level}</h4>;
    case 5:
      return <h5>{children}{level}</h5>;
    case 6:
      return <h6>{children}{level}</h6>;
    default:
      throw Error('Unknown level: ' + level);
  }
}

```

createContextに値を渡して、それをuseContextの中に入れて使うじゃ足りないんですね。
コンテクストの提供というものをすればいいのか、どうすればSectionに指定した値を呼べるのだろう...

### ステップ 3：コンテクストを提供する

ステップ2までの実装では、 
`LevelContext -> Heading.jsx `
と値が渡されていました。これを
`LevelContext -> Section.jsx -> Heading.jsx`
とすれば良さそうです。

```diff
+ import { LevelContext } from './LevelContext.js';

export default function Section({ level, children }) {
  return (
    <section className="section">
+    <LevelContext.Provider value={level}>
        {children}
+    </LevelContext.Provider>
    </section>
  );
}
```

LevelContext.Provider というものが出てきました。([プロバイダって翻訳すると何？](https://e-words.jp/w/%E3%83%97%E3%83%AD%E3%83%90%E3%82%A4%E3%83%80.html#:~:text=%E3%83%97%E3%83%AD%E3%83%90%E3%82%A4%E3%83%80%EF%BC%88provider%EF%BC%89%E3%81%A8%E3%81%AF%E3%80%81,%E6%84%8F%E5%91%B3%E3%82%92%E6%8C%81%E3%81%A4%E8%8B%B1%E5%8D%98%E8%AA%9E%E3%80%82))
これを行うことで、LevelContext.Provider配下にいるcomponentに対して `コンテクストの提供` が可能となります。

いったんまとめます。

##### porpsで値をバケツリレーせず、共通した値を孫にも渡したい
 - useContextを使う
    - 準備する `const hoge = createContext(初期値)`
    - 提供する `<hoge.Provider value={値}>` で囲む (親側で渡したい値を指定)
    - 呼び出す `const huga = useContext(hoge)` 値を呼び出す

<b>...準備がややこしいんですよね!!!!</b>

ただ、仕組みはわかりました！

もちろんオブジェクトも渡せます

```jsx
import { createContext, useContext } from 'react';

const ThemeContext = createContext(null);

export default function MyApp() {
  const theme = {
    mode : "dark",
    font : 20
  }
  return (
    <ThemeContext.Provider value={theme}>
      <Form />
    </ThemeContext.Provider>
  )
}
```

---

## まとめ
useContextを使うべく、公式を追ってみました。
準備が必要という時点でちょっと複雑に感じますが、わかってしまえば大丈夫ですね！

もう一歩深掘るには [`createContext`](https://ja.react.dev/reference/react/createContext#createcontext)  を理解する必要がありそうです！
(何を返すのか、中身がどうなっているのか)

次回は [`createContext`](https://ja.react.dev/reference/react/createContext#createcontext) を追ってみることにします！