【React】初学者、Contextを使ってみる。

## はじめに
現場でContextを使った実装を任された際に手こずった(現在進行形)ので、もっと単純化してContextの使い方を習得しようという意図をもって作成したものについて備忘録を残します。
本来であればTypescriptで書くべきなのですが、そちらも初学者のため、今回はjavascriptを使って書いています。

## Contextとは？
リファレンスを見てみましょう。

***「コンテクストを用いると、コンポーネントは props を渡すことなく、離れた親要素から情報を取得できるようになります。例えば、アプリの最上位のコンポーネントが、現在の UI テーマをコンポーネントの階層に関係なくすべてのコンポーネントに渡すことができます。」***


説明は上記の通りなのですが、
`Context`を使わない場合、`props`で「親→子→孫」のように下のコンポーネントに情報を渡していくことになります。しかしこれにはデメリットがあります。

>・propsを親から受けて孫に渡すという役割を持つコンポーネントが出来る。
・コンポーネント階層が深くなるとコードが読みにくく、保守性が低下する。

そして***これらを解決してくれる***のが今回の`Context`ということになります。

## さっそく作ってみた
今回はContextで管理された値を画面に表示する機能を実装していきます。
完成形はこんな感じ。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3814555/ad44fd40-ad28-5d66-ad1e-3470c27fae29.png)



### ①作成したコンポーネント

```react:App.js
import { Form } from "./Form";
import { TextContainer } from "./TextContainer";
import { TextProvider } from "./TextProvider";

export const App = () => {
  return (
    <div>
      <TextProvider>
        <Form />
        <TextContainer />
      </TextProvider>
    </div>
  );
};
```
***TextProvider***:Contextを作成し、値を渡す
***Form***:テキストボックスとボタン
***TextContainer***:Contextで管理されている値を表示

### ②Contextの作成
```react:TextProvider.jsx
import { createContext, useState } from "react";

//コンテキストの作成
export const Text = createContext();

export const TextProvider = ({ children }) => {
  const [texts, setTexts] = useState([]);

  //Formコンポーネントのテキストボックスの内容を配列textsに追加する
  const addText = (inputValue) => {
    setTexts((prev) => [...prev, inputValue]);
  };
  
  //Providerコンポーネントで子コンポーネントを包むことで、Provider配下で利用するコンテキストを決定
  return <Text.Provider value={{ texts, addText }}>{children}</Text.Provider>;
};
```
まずContextオブジェクトを作成する必要があり、その際には`createContext`を使用します。
引数は初期値を入れることが出来ます。
```react
//コンテキストの作成
export const Text = createContext();
```

次に子孫コンポーネントで値を利用できるように、`Provider`で子コンポーネントを包んであげます。
`[作成したコンテキストオブジェクト名].Provider value={渡したい値}`という形式で記載し、`value`には子孫コンポーネントに渡したい値を書いてあげます。
今回は動的に変化する値を画面に表示させたいので`State`で管理している値を渡しています。
```react
 //Providerコンポーネントで子コンポーネントを包むことで、Provider配下でコンテキストが利用出来る
  return <Text.Provider value={{ texts, addText }}>{children}</Text.Provider>;
```

### ③値を画面に表示させる

```react:TextContainer.jsx
import { useContext } from "react";
import { Text } from "./TextProvider";

export const TextContainer = () => {
  //渡された値を使用する
  const { texts, addText } = useContext(Text);

  return (
    <div>
      {texts.map((text, index) => {
        return (
          <div>
            <p>
              <span>{index + 1}.</span>
              {text}
            </p>
          </div>
        );
      })}
    </div>
  );
};

```
渡されたコンテキストの値を子孫コンポーネント側で使用するためには`useContext`を使います。
`useContext(作成したコンテキストオブジェクト名)`という形式で使用し、渡された値を受け取ることが出来ます。

```react
 //渡された値を使用する
  const { texts, addText } = useContext(Text);
```
::: note warn 
注意
作成したContextオブジェクトのimportも忘れずにしましょう。
こんなことで時間が溶けてしまいました、、、
```react
import { Text } from "./TextProvider";
```
:::

### ④テキストボックスとボタンの作成
```react:Form.jsx
import { useContext, useState } from "react";
import { Text } from "./TextProvider";

export const Form = () => {
  const { texts, addText } = useContext(Text);
  const [value, setValue] = useState();

  const onChangeText = (e) => {
    setValue(e.target.value);
  };

  const handleClick = (value) => {
    addText(value);
    setValue("");
  };

  return (
    <div>
      <input value={value} onChange={onChangeText} />

      <button
        onClick={() => {
          handleClick(value);
        }}
      >
        追加
      </button>
    </div>
  );
};

```
Contextで管理されている`addText`を使用するために`useContext`を使って値を受け取っています。

## 完成

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3814555/a5ff974f-0644-3274-902f-d2ae57ba4b2b.png)