1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

React useContextとuseStateを使って型定義した配列を制御する

Last updated at Posted at 2023-02-09

概要

前回の記事の応用で、型定義した配列のStateをContext化できるか確認します。

number[]で実装できるか確認する(前回)

CustomType[]で実装できるか確認する。(本記事)
実装した感想としては、number[]で実装できれば型定義した配列も簡単です。

開発環境

React:18.20
css:sytled-jsx
言語:TypeScript

実装

以下3つのファイルを作成します。

ファイル名 説明
subItems.d.ts 型定義ファイル
index.tsx 親コンポーネント
subItemComponent.tsx 子コンポーネント

完成図の様子
下gifアニメはボタンを押して、コンポーネントの増減、コンポーネントの要素(amount)を増やす操作を行っている様子です。
Context_例.gif

ボタン類の説明

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

実装

1.型定義ファイルの作成

subItem.d.ts
export type SubItem={
	id: number;
	name:string;
	price:number;
	amount:number;
}

2.親コンポーネントの作成(Providerの設定)

詰まった点は特になし

index.tsx
import { createContext, useState } from "react"
import SubItemComponent from "./subItemComponent";
import { SubItem } from "./subItem"

export const SubItemContext = createContext();

export default function Index() {
	const[subItems, setSubItems] = useState<SubItem[]>([{id: 1, name: "subItem1",price:100,amount:1}, {id: 2, name: "subItem2",price:300,amount:1}])

    // 各要素のnameを出力
	let message : string = ""
	subItems.map((item: SubItem, index: number) => {
		message += item.name + " ,"
	})
	console.log(message)
	return(
		<>

			{subItems.map((item: SubItem, index: number) => {
				const values={subItems,setSubItems,index}
				return(
					<SubItemContext.Provider value={values} key={index}>
						<SubItemComponent />
					</SubItemContext.Provider>
				)
			})}
			<div></div>
		</>
	)
}

3.子コンポーネントの作成(useContextの設定)

詰まった点は特になし

subItemComponent.tsx
import { useContext } from "react"
import { SubItemContext } from "."
import { SubItem } from "./subItem"

export default function SubItemComponent() {
	const {subItems,setSubItems,index} = useContext(SubItemContext)	
	return(
		<div className="Layout">
			<div className="SubLayout">
				<div>ID:{subItems[index].id}</div>
				<div>名前:{subItems[index].name}</div>
			</div>
			<div className="SubLayout">
				<div>値段:{subItems[index].price}</div>
				<div>個数:{subItems[index].amount}</div>
			</div>
			<style jsx>{`				
				// 枠線-要素を縦方向に配置
				.Layout{
					display:flex;
					flex-direction:column;
					border:1px solid black;
					width:200px;
				}
				//要素を横方向に配置
				.SubLayout{
					display:flex;
					flex-direction:row;
				}
			`}</style>	

		</div>
	)

}

4.ボタン系の実装

index.tsx

import { createContext, useState } from "react"
import SubItemComponent from "./subItemComponent";
import { SubItem } from "./subItem"

export const SubItemContext = createContext();

export default function Index() {
	const[subItems, setSubItems] = useState<SubItem[]>([{id: 1, name: "subItem1",price:100,amount:1}, {id: 2, name: "subItem2",price:300,amount:1}])

+	const addSubItemHandler = () => {
+		setSubItems([...subItems,{id: subItems.length + 1, name: "subItem" + (subItems.length + 1),price:100,amount:1}])
+	}
	let message : string = ""
	subItems.map((item: SubItem, index: number) => {
		message += item.name + " ,"
	})
	console.log(message)
	return(
		<>

			{subItems.map((item: SubItem, index: number) => {
				const values={subItems,setSubItems,index}
				return(
					<SubItemContext.Provider value={values} key={index}>
						<SubItemComponent />
					</SubItemContext.Provider>
				)
			})}
			<div></div>
+			<button onClick={addSubItemHandler}>子コンポーネントを追加</button>
		</>
	)
}
subItemComponent.tsx
import { useContext } from "react"
import { SubItemContext } from "."
import { SubItem } from "./subItem"

export default function SubItemComponent() {
	const {subItems,setSubItems,index} = useContext(SubItemContext)	

+	// amountを+1する
+	const addHandler = () => {
+		setSubItems(subItems.map((subItem:SubItem,i:number) => i === index ?
+		// amountだけ更新したら、他の要素が消えるので全部(id,name,price)更新する必要あり
+		 {id:subItem.id,amount:subItem.amount + 1,name:subItem.name,price:subItem.price} : subItem)
+	)}


	// 子コンポーネントの存在を削除する
+	const deleteHandler = ()=>{
+		setSubItems(subItems.filter((subItem:SubItem,i:number) => i !== index))
+	}
	return(
		<div className="Layout">
			<div className="SubLayout">
				<div>ID:{subItems[index].id}</div>
				<div>名前:{subItems[index].name}</div>
			</div>
			<div className="SubLayout">
				<div>値段:{subItems[index].price}</div>
				<div>個数:{subItems[index].amount}</div>
			</div>
			<div className="SubLayout">
+				<button onClick={addHandler}>追加</button>
+				<button onClick={deleteHandler}>削除</button>
			</div>
			<style jsx>{`				
				// 枠線-要素を縦方向に配置
				.Layout{
					display:flex;
					flex-direction:column;
					border:1px solid black;
					width:200px;
				}
				//要素を横方向に配置
				.SubLayout{
					display:flex;
					flex-direction:row;
				}
			`}</style>	

		</div>
	)

}

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?