概要
useContextとuseStateを使ってnumber型の配列のStateの実装方法を投稿します。
開発環境
IDE:VSCode
React:18.20
サンプル
動かしているときの様子(gifアニメ)
右側のログはStateの状態を出力しています。
ボタンの名前 | 機能 |
---|---|
削除 | 対応する子コンポーネントが削除されます。 |
追加 | 対応する子コンポーネントのcountが+1されます。 |
ChildCを追加 | 子コンポーネントを追加します。 |
実装
ファイルは2つ作ります。
1.Stateを管理するファイル(親コンポーネント)
2.1のStateを使うコンポーネント(子コンポーネント)
1.親コンポーネント側の設定(Providerの設定)
Providerで子コンポーネントに値を渡します。
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側に渡している
// 子コンポーネント1つにつき、別々のindexを渡すため、1つのContextを作成している。
<UserCount.Provider value={values} key={index}>
<ChildC />
</UserCount.Provider>
);
})}
<div></div>
</>
);
}
2.子コンポーネントの設定(useContextの設定)
useContextを使って、親コンポーネントのvaluesを受け取ります。
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の配列の処理)
以下処理を実装します。
1,2で作ったファイルにボタン押下処理を追加します。
書き方に癖があって試行錯誤しました。Stateの配列は普通のArrayのようにpop pushでやるとエラーになります。
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つにつき、1つのContextを作成している。(子:Provider=1:1の割合 多:1だとNG)
<UserCount.Provider value={values} key={index}>
<ChildC />
</UserCount.Provider>
);
})}
<div></div>
+ <button onClick={addHandler}>ChildCを追加</button>
</>
);
}
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]を+1するボタン
+ 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の設定の仕方
配列のStateに追加削除する方法