【保存版】React Hooksで配列内のオブジェクトをonChangeで更新:サンプルコード付き
React Hooksで配列内のオブジェクトのステートをonChangeで更新する方法
ステートの更新例
以下の例では、useState
フックを使用して、items
という名前のステートを定義しています。このステートは、name
とprice
というプロパティを持つオブジェクトの配列です。
const [items, setItems] = useState([
{ name: '商品A', price: 100 },
{ name: '商品B', price: 200 },
]);
このステートを更新するには、setItems
関数を使用します。この関数は、新しい配列を引数として渡す必要があります。新しい配列は、元の配列の複製を作成し、更新したいオブジェクトを変更したものである必要があります。
以下は、onChange
イベントを使用してitems
ステートを更新する例です。
const handleChange = (event, index) => {
const newItems = [...items];
newItems[index].name = event.target.value;
setItems(newItems);
};
return (
<div>
{items.map((item, index) => (
<input
key={index}
value={item.name}
onChange={(event) => handleChange(event, index)}
/>
))}
</div>
);
この例では、handleChange
という関数が定義されています。この関数は、event
とindex
を引数として受け取ります。event
は、onChange
イベントオブジェクトであり、index
は更新したいオブジェクトのインデックスです。
まず、handleChange
関数は、items
ステートの複製であるnewItems
という新しい配列を作成します。次に、newItems
配列のindex
番目のオブジェクトのname
プロパティを、event.target.value
に更新します。最後に、setItems
関数を呼び出して、newItems
配列を新しいステートとして設定します。
その他の注意点
- Reactは、ステートの変化を検出してコンポーネントを再描画します。そのため、ステートを直接変更するのではなく、新しいステートを作成して設定する必要があります。
- オブジェクトのプロパティを更新するには、スプレッド構文を使用してオブジェクトを複製し、更新したいプロパティのみを変更する必要があります。
- 配列の要素を追加または削除するには、
push()
,pop()
,shift()
,unshift()
などの配列操作メソッドを使用する必要があります。
サンプルコード:React Hooksで配列内のオブジェクトのステートをonChangeで更新
import React, { useState } from 'react';
const App = () => {
const [items, setItems] = useState([
{ name: '商品A', price: 100, category: { type: '雑貨' } },
{ name: '商品B', price: 200, category: { type: '衣類' } },
]);
const handleChange = (event, index) => {
const newItems = [...items];
newItems[index][event.target.name] = event.target.value;
setItems(newItems);
};
const addProduct = () => {
const newItems = [...items];
newItems.push({ name: '', price: 0, category: { type: '雑貨' } });
setItems(newItems);
};
const removeProduct = (index) => {
const newItems = [...items];
newItems.splice(index, 1);
setItems(newItems);
};
const changeCategoryType = (index, categoryType) => {
const newItems = [...items];
newItems[index].category.type = categoryType;
setItems(newItems);
};
return (
<div>
<h2>商品リスト</h2>
{items.map((item, index) => (
<div key={index}>
<input
type="text"
name="name"
value={item.name}
onChange={(event) => handleChange(event, index)}
/>
<input
type="number"
name="price"
value={item.price}
onChange={(event) => handleChange(event, index)}
/>
<select
name="categoryType"
value={item.category.type}
onChange={(event) => changeCategoryType(index, event.target.value)}
>
<option value="雑貨">雑貨</option>
<option value="衣類">衣類</option>
<option value="家具">家具</option>
</select>
<button onClick={() => removeProduct(index)}>削除</button>
</div>
))}
<button onClick={addProduct}>商品を追加</button>
</div>
);
};
export default App;
このコードでは、以下の操作が可能です。
- 商品の名前と価格を編集: 各商品の入力欄で値を変更することで、
items
ステート内の対応するオブジェクトのプロパティが更新されます。 - 商品のカテゴリーを変更: 各商品のドロップダウンメニューからカテゴリータイプを選択することで、
items
ステート内の対応するオブジェクトのcategory.type
プロパティが更新されます。 - 商品を追加:
商品を追加
ボタンをクリックすると、items
ステートに新しい空のオブジェクトが追加されます。
このサンプルコードは、React Hooksを使用して配列内のオブジェクトのステートをonChange
イベントで更新する方法を理解するための出発点として役立ちます。
このサンプルコード以外にも、さまざまな方法でステートを更新できます。以下に、いくつかの例を示します。
- ネストされたオブジェクトのプロパティを更新: オブジェクト内にネストされたオブジェクトがある場合、スプレッド構文を使用してネストされたレベルにアクセスして更新することができます。
- 条件付きでステートを更新:
onChange
イベントハンドラー内で条件式を使用して、ステートを更新するかどうかを判断することができます。 - 非同期的にステートを更新:
useState
フックの第二引数として関数を渡すことで、非同期的にステートを更新することができます。
これらの例は、React Hooksの柔軟性を示すほんの一例です。詳細については、Reactのドキュメントを参照してください。
React Hooksで配列内のオブジェクトのステートをonChangeで更新するその他の方法
useReducer
フックは、ステートを更新するためのより複雑なロジックを管理するのに役立ちます。ステートの更新を複数のreducer
関数に分割し、より良いコードの組織化と再利用性を提供します。
const reducer = (state, action) => {
switch (action.type) {
case 'UPDATE_ITEM':
return {
...state,
items: state.items.map((item, index) =>
index === action.index ? { ...item, ...action.data } : item
),
};
case 'ADD_ITEM':
return {
...state,
items: [...state.items, action.data],
};
case 'REMOVE_ITEM':
return {
...state,
items: state.items.filter((item, index) => index !== action.index),
};
default:
return state;
}
};
const App = () => {
const [state, dispatch] = useReducer(reducer, {
items: [
{ name: '商品A', price: 100, category: { type: '雑貨' } },
{ name: '商品B', price: 200, category: { type: '衣類' } },
],
});
const handleChange = (event, index) => {
dispatch({
type: 'UPDATE_ITEM',
index,
data: { [event.target.name]: event.target.value },
});
};
const addProduct = () => {
dispatch({ type: 'ADD_ITEM', data: { name: '', price: 0, category: { type: '雑貨' } } });
};
const removeProduct = (index) => {
dispatch({ type: 'REMOVE_ITEM', index });
};
const changeCategoryType = (index, categoryType) => {
dispatch({ type: 'UPDATE_ITEM', index, data: { category: { type: categoryType } } });
};
return (
<div>
{/* ... (上記と同じレンダリングコード) */}
</div>
);
};
この例では、useReducer
フックを使用して、items
ステートの更新を管理するreducer
関数を定義しています。reducer
関数は、type
プロパティを持つアクションオブジェクトに基づいてステートを更新します。
handleChange
、addProduct
、removeProduct
、changeCategoryType
などの各関数のアクションオブジェクトを作成して、dispatch
関数に渡すことで、ステートを更新できます。
immer
ライブラリは、イミュータブルなデータを効率的に更新するための便利なツールです。immer
を使用すると、ステートを直接変更する代わりに、新しいステートの複製を作成して変更を適用することができます。これにより、コードがより読みやすく、デバッグしやすくなります。
import { useReducer, produce } from 'immer';
const reducer = (state, action) => {
return produce(state, (draftState) => {
switch (action.type) {
case 'UPDATE_ITEM':
draftState.items[action.index][event.target.name] = event.target.value;
break;
case 'ADD_ITEM':
draftState.items.push(action.data);
break;
case 'REMOVE_ITEM':
draftState.items.splice(action.index, 1);
break;
}
});
};
// ... (Appコンポーネントはreducerを使用する)
const handleChange = (event, index) => {
dispatch({
type: 'UPDATE_ITEM',
index,
data: { [event.target.name]: event.target.value },
});
};
// ... (その他の関数はreducerを使用する)
この例では、immer
ライブラリを使用して、reducer
関数内でステートを更新する方法を示しています。produce
関数を使用して、ステートの複製を作成し、その複製を変更します。変更が完了したら、return
ステートメントを使用して
javascript reactjs react-hooks