React useContextとuseStateを使ってnumber型の配列を制御する

# 概要
useContextとuseStateを使ってnumber型の配列のStateの実装方法を投稿します。


# 開発環境
IDE:VSCode
React:18.20

# サンプル
動かしているときの様子（gifアニメ）
右側のログはStateの状態を出力しています。
![context-check.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2710623/3c9b6b06-61a4-b3fc-c95d-fa2d868b3f43.gif)




ボタンの名前|機能
---|----
削除|対応する子コンポーネントが削除されます。
追加|対応する子コンポーネントのcountが+1されます。
ChildCを追加|子コンポーネントを追加します。



# 実装
ファイルは２つ作ります。
１．Stateを管理するファイル（親コンポーネント）
２．１のStateを使うコンポーネント（子コンポーネント）

# 1.親コンポーネント側の設定（Providerの設定）
Providerで子コンポーネントに値を渡します。
```tsx:index.tsx
import { createContext, useState } from "react";
import ChildC from "./childC";

// Contextを作成
export const UserCount = createContext();

// 親コンポーネント
export default function Index() {
  const [counts, setCounts] = useState<number[]>([1, 2]);
  console.log(counts);
  return (
    <>
      {counts.map((item: number, index: number) => {
        // useStateとindexを渡している
        // indexがないと、子コンポーネント側で自身の配列を特定できない
        const values = { counts, setCounts, index };
        return (
          // valuesの値をChildC側に渡している
          // 子コンポーネント１つにつき、別々のindexを渡すため、1つのContextを作成している。
          <UserCount.Provider value={values} key={index}>
            <ChildC />
          </UserCount.Provider>
        );
      })}
      <div></div>
    </>
  );
}
```

# 2.子コンポーネントの設定(useContextの設定)
useContextを使って、親コンポーネントのvaluesを受け取ります。
```tsx:childC.tsx
import { useContext } from "react";
import { UserCount } from ".";

// 子コンポーネント
// 親からContextを受け取っている
export default function ChildC() {
  const { counts, setCounts, index } = useContext(UserCount);
  return (
    <>
      <div>番号{counts[index]}</div>
    </>
  );
}

```


# 3.ボタン類の実装（Stateの配列の処理）
以下処理を実装します。
１，２で作ったファイルにボタン押下処理を追加します。
書き方に癖があって試行錯誤しました。Stateの配列は普通のArrayのようにpop pushでやるとエラーになります。

```diff_tsx:index.tsx
import { createContext, useState } from "react";
import ChildC from "./childC";

// Contextを作成
export const UserCount = createContext();

// 親コンポーネント
export default function Index() {
  const [counts, setCounts] = useState<number[]>([1, 2]);
+  const addHandler = () => {
+    // スプレッド構文で表現
+    // count.push(1)でやるとエラーになる
+    setCounts([...counts, 1]);
+  };
  console.log(counts);
  return (
    <>
      {counts.map((item: number, index: number) => {
        // useStateとindexを渡している
        // indexがないと、子コンポーネント側で自身の配列を特定できない
        const values = { counts, setCounts, index };
        return (
          // valuesの値をChildC側に渡している
          // 別々のindexを渡すため子コンポーネント１つにつき、1つのContextを作成している。(子:Provider=1:1の割合 多:1だとNG)
          <UserCount.Provider value={values} key={index}>
            <ChildC />
          </UserCount.Provider>
        );
      })}
      <div></div>
+      <button onClick={addHandler}>ChildCを追加</button>
    </>
  );
}

```

```diff_tsx:childC.tsx
import { useContext } from "react";
import { UserCount } from ".";

// 子コンポーネント
// 親からContextを受け取っている
export default function ChildC() {
  const { counts, setCounts, index } = useContext(UserCount);

+  // 子コンポーネントの存在を削除する
+  const deleteHandler = () => {
+    // counts.pop(index)でやるとエラーになる
+    setCounts(counts.filter((count: number, i: number) => i !== index));
+  };
+  // count[index]を＋１するボタン
+  const addHandler = () => {
+    // index番目の時だけcountを追加している
+    setCounts(
+      counts.map((count: number, i: number) =>
+        i === index ? count + 1 : count
+      )
+    );
+  };

  return (
    <>
      <div>番号{counts[index]}</div>
+      <button onClick={addHandler}>追加</button>
+      <button onClick={deleteHandler}>削除</button>
    </>
  );
}

```

# 参考資料

Contextの設定の仕方

https://reffect.co.jp/react/react-usecontext-understanding#Context

配列のStateに追加削除する方法

https://qiita.com/itachi/items/4184b2afc35b55b45568