React useContextとuseReducerのアウトプット

# はじめに
useContextとuseReducerについて勉強したため、アウトプットをする。
# useContextとは
React Hooksの一つ。親コンポーネントから子コンポーネントにpropsを使わずにデータを渡すことができる。そのため、propsのバケツリレーをしなくて済む。
useContextを記述するファイルを作成することで、親、子、孫どこからでもデータにアクセスが可能となる。
![スクリーンショット 2023-10-25 110125.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3582046/21a2a2d7-b874-03d2-c3c6-79c86f3fa4f7.png)

![スクリーンショット 2023-10-25 111106.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3582046/c01b81e4-4784-dfea-b7f6-24612303d97d.png)

useReducerは前回アウトプットした
https://qiita.com/naoyuki2/items/5b88e9b069bdaf8acd85

# 完成品
今回のコードはコンポーネントの数が少ないため、useContextの恩恵をあまり得られない。もっとコンポーネントが増えると真価を発揮するだろう。
![スクリーンショット 2023-10-25 102519.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3582046/cef07fd8-ac7b-7973-6f76-9b0e9c5d5a5c.png)

```diff_javascript
// NumContext.js
import { createContext, useContext, useReducer } from "react";//ポイント１

const NumContext = createContext();//ポイント２
const NumDispatchContext = createContext();

const reducer = (prev, { type, payload }) => {
  switch (type) {
    case "change":
      return payload.value;
    default:
      throw new Error("不明なactionです。");
  }
};

const NumProvider = ({ children }) => {//ポイント３
  const [state, dispatch] = useReducer(reducer, "");

  return (
    <NumContext.Provider value={state}>
      <NumDispatchContext.Provider value={dispatch}>
        {children}
      </NumDispatchContext.Provider>
    </NumContext.Provider>
  );
};

const useNum = () => {//ポイント４
  return useContext(NumContext);
};
const useNumDispatch = () => {
  return useContext(NumDispatchContext);
};

export { NumProvider, useNum, useNumDispatch };
```

```diff_javascript
//Example.js
import { NumProvider } from "./context/NumContext";//ポイント１
import Input from "./components/Input";

const Example = () => {
  return (
    <NumProvider>//ポイント２
      <Input />
    </NumProvider>
  );
};

export default Example;
```

```diff_javascript
//Input.js
import { useNum } from "../context/NumContext";//ポイント１
import { useNumDispatch } from "../context/NumContext";

const Input = () => {
  const state = useNum();//ポイント２
  const dispatch = useNumDispatch();

  return (
    <>
      <input
        type="number"
        value={state}
        onChange={(e) =>
          dispatch({ type: "change", payload: { value: e.target.value } })
        }
      />
      <h1>入力値:{state}</h1>
    </>
  );
};

export default Input;
```
# 解説(NumContext.js)
## ポイント１
useContextを利用する場合は、createContext,useContextをインポートする。今回はuseReducerも利用するため、インポートしている。
```diff_javascript
import { createContext, useContext, useReducer } from "react";//ポイント１
```
## ポイント２
createContext()で定数を宣言すると、その定数をすべてのコンポーネントで使用できるようになる。()の中は初期値が入力できる。今回は入力しない。
```diff_javascript
const NumContext = createContext();//ポイント２
const NumDispatchContext = createContext();
```
## ポイント３
NumContext.Providerで子コンポーネント(children)を囲むことで、NumContextが使用できるようになる。Providerの後にvalueを指定することでNumContextの中身を指定できる。(NumDispatchContextも同様)
```diff_javascript
const NumProvider = ({ children }) => {//ポイント３
  const [state, dispatch] = useReducer(reducer, "");

  return (
    <NumContext.Provider value={state}>
      <NumDispatchContext.Provider value={dispatch}>
        {children}
      </NumDispatchContext.Provider>
    </NumContext.Provider>
  );
};
```
## ポイント４
createContext()で宣言された定数を使用する場合は、useContext()を使う必要がある。useContextを子コンポーネントごとにインポートするのはめんどくさいのでNumContext.js内で完結させている。子コンポーネントはuseNumやuseNumDispatchをインポートするだけでよい。
```diff_javascript
const useNum = () => {//ポイント４
  return useContext(NumContext);
};
const useNumDispatch = () => {
  return useContext(NumDispatchContext);
};

export { NumProvider, useNum, useNumDispatch };
```
# 解説(Example.js)
## ポイント１
NumContext.jsで定義した、NumProviderをインポートする。
```diff_javascript
import { NumProvider } from "./context/NumContext";//ポイント１
```
## ポイント２
子コンポーネントをNumProviderで囲むことで、NumContext.js内で定義した二つのContextを子コンポーネント内で使用できる。NumContext.js内のchildrenのところに<Input />がレンダリングされている。
```diff_javascript
    <NumProvider>//ポイント２
      <Input />
    </NumProvider>
```
# 解説(Input.js)
## ポイント1
NumContextからuseNumとuseNumDispatchをインポートして、Input.js内でNumContexとNumDispatchContextを使えるようにしている。
```diff_javascript
import { useNum } from "../context/NumContext";//ポイント１
import { useNumDispatch } from "../context/NumContext";
```
## ポイント２
stateとdispatchにそれぞれuseNum,useNumDispatchを代入することで、useContextのことを気にせずにuseReducerを使える。
```diff_javascript
const state = useNum();//ポイント２
const dispatch = useNumDispatch();
```