当サイトは、アフィリエイト広告を利用しています
useStateでオブジェクト配列をstateに設定した場合の
操作をまとめる。
useStateの基本的な使い方については下記記事で紹介していますので
初歩的なところから知りたい場合はご参照ください!
簡単なtodoリストを作成する画面
機能としては下記ができる。
import "./styles.css";import React, { useState, useRef } from "react";export default function App() {// 初期値const initialState = [];// 登録inputconst registInput = useRef(null);// useStateconst [list, setList] = useState(initialState);// 更新内容input入力時のstate更新//リストから更新対象のオブジェクトのtargetプロパティのみを更新するconst inputUpdate = (event, i) => {setList(// mapで更新対象オブジェクトのみを変更した新規配列を作成し、stateにセットするlist.map((val, index) =>index === i ? { ...val, target: event.target.value } : { ...val }));};// todolistのクリアconst clear = () => setList(initialState);// todolistへの追加const add = () => {// 値がない場合は追加しないif (!registInput.current.value) return;setList((prevList) => [...prevList,{ title: registInput.current.value, target: "" }]);};// todolistの更新const upd = (i) => {setList(// 更新内容inputを変更した時点でstateの配列に格納されているオブジェクトのtargetは// 更新されているため、更新ボタン押下時は更新対象オブジェクトのterget→titleで更新した// 新規配列をmapで作成し、stateにセットするlist.map((val, index) =>index === i ? { ...val, title: val.target } : { ...val }));};// todolistの削除const del = (i) => {setList(list.filter((x, index) => index !== i));};return (<div className="App"><h1>todolistの削除</h1><div><input type="text" ref={registInput}></input><button className="button" onClick={add}>登録</button><button className="button" onClick={clear}>クリア</button></div><h1 style={{ textAlign: "left" }}>ToDo List</h1><div style={{ textAlign: "left" }}>{list.map((todoList, i) => (<li key={i}><button className="button" onClick={() => del(i)}>削除</button>|{todoList.title}<inputtype="text"value={todoList.target}onChange={(e) => inputUpdate(e, i)}></input><button className="button" onClick={() => upd(i)}>更新</button></li>))}</div></div>);}
初期値としてstateに配列を設定する。
// 初期値const initialState = [];// useStateconst [list, setList] = useState(initialState);
inputに値を入力し、登録ボタンを押下したらtodoが追加される機能を実装する。
登録ボタン時にinputに入力されている値を取得するために
useRefでinputの値をregistInputで保持するようにしておく。
※useStateでも可能
// 登録inputconst registInput = useRef(null);// ~省略~<inputtype="text"ref={registInput}></input>
inputで入力した値を、オブジェクトにしてsetStateで追加する
※追加と書いたが実際は新しいオブジェクトが追加された新しい配列を生成している
// todolistへの追加const add = () => {// 値がない場合は追加しないif (!registInput.current.value) return;setList((prevList) => [// 直前のstateをスプレッド構文で展開...prevList,// 新規オブジェクトを追加{ title: registInput.current.value, target: "" }]);};
下記ようにsetState内の位置を入れ替えれば
追加するtodoを最下部か最上部のどちらに入れるか変更できる
// todolistへの追加const add = () => {// 値がない場合は追加しないif (!registInput.current.value) return;setList((prevList) => [// 新規オブジェクトを追加{ title: registInput.current.value, target: "" },// 直前のstateをスプレッド構文で展開...prevList]);};
inputに入力した値で更新ボタン押下時に対象のtodoを更新する
// ~<inputtype="text"value={todoList.target}onChange={(e) => inputUpdate(e, i)}></input><button className="button" onClick={() => upd(i)}>更新</button>// ~
inputにはstate(list)のtargetが表示されている。
inputUpdateではinputが変更されたタイミングで
state(list)のtargetを更新する
※targetは更新後の値を保持している
// 更新内容input入力時のstate更新//リストから更新対象のオブジェクトのtargetプロパティのみを更新するconst inputUpdate = (event, i) => {setList(// mapで更新対象オブジェクトのみを変更した新規配列を作成し、stateにセットするlist.map((val, index) =>//indexが一致していればtargetを上書きindex === i ? { ...val, target: event.target.value } : { ...val }));};
これでlistに格納されているオブジェクトは
{title:"更新前の値(画面に表示のみ)",target:"更新後の値(inputに表示)"}
の状態となる。
更新ボタン押下でtodoを更新する。
処理内容としては更新対象のtitleをtargetで上書きする
// todolistの更新const upd = (i) => {setList(// 更新内容inputを変更した時点でstateの配列に格納されているオブジェクトのtargetは// 更新されているため、更新ボタン押下時は更新対象オブジェクトのterget→titleで更新する// 新規配列をmapで作成し、stateにセットするlist.map((val, index) =>//indexが一致した場合はtitleをtargetで上書きするindex === i ? { ...val, title: val.target } : { ...val }));};
stateのlistから対象のtodoを削除する。
stateのlistからfilterを使って削除対象以外のlistを再作成する
削除ボタン押下でdel処理を呼び出す。
// ~{list.map((todoList, i) => (<li key={i}><button className="button" onClick={() => del(i)}>削除</button>// ~</li>// ~
filterを使って、一致した要素を削除する
// todolistの削除const del = (i) => {// indexが一致したtodoは除去するsetList(list.filter((_, index) => index !== i));};
useStateでオブジェクト配列を扱う場合、スプレッド構文とmapやfilterなどを
を使う必要がある。
配列でスプレッド構文を使う
setList((prevList) => [...prevList,{ title: registInput.current.value, target: "" }]);
新規配列内で変更前のlistをスプレッド構文で展開後、オブジェクトを新規追加する
mapとオブジェクトでスプレッド構文を使う
const upd = (i) => {setList(list.map((val, index) =>index === i ? { ...val, title: val.target } : { ...val }));};
mapを使って更新対象のオブジェクトをスプレッド構文を利用して更新(上書き)していく
オブジェクト内でスプレッド構文を使った場合、同じkeyがあれば後勝ちで上書きされる。
※今回はindexで更新しているが実際は、オブジェクト内にkeyを持たせた方がいい
filterを使う
const del = (i) => {setList(list.filter((_, index) => index !== i));};
filterで削除対象を省く
実際に動作が確認できるソースをおいておく