LESSON 05 · 約35分
配列を表示し、不変に更新する
map・key・filterを使い、項目の同一性を保ちながら一覧を変更します。
コードを試す前に
01のVite reactテンプレート(JavaScript/JSX)を使います。特記のないApp.jsxは、そのレッスンだけで動く独立した例です。例同士を連結しないでください。
短い学習用の例です。各App.jsxは独立した例で、順に追記して一つの完成品にする形式ではありません。ファイル名、依存関係、未定義部分の前提は注記に記載します。問題内の抜粋や空欄は、そのまま実行するための完成コードではありません。
開発環境の準備を確認する →このレッスンでわかること
- 安定したIDをkeyにできる
- 元の配列やオブジェクトを変えずに項目を更新できる
mapで部品の配列を作る
items.mapは項目ごとにJSXを返します。直接返す最上位の要素にkeyを指定します。keyは、追加・削除・並び替え後も同じ項目を見分ける手がかりです。データが持つ安定したidを使い、描画するたびに乱数を作りません。順序が変わる一覧では配列の添字も避けます。
stateは置き換える
追加なら[...items, newItem]、削除ならfilter、特定項目の変更ならmapを使います。配列をコピーしただけでは中のオブジェクトは同じ参照です。変える項目も{ ...item, done: !item.done }のように新しく作り、他の項目はそのまま返します。
識別子と表示を分ける
タイトルは重複したり編集されたりします。idを別に持つと、どの行を操作するかが明確です。key自体は子コンポーネントへ通常のpropsとして渡されません。子でもIDを使うならid={item.id}を別に渡します。完了件数はitemsから計算すれば、別stateとの同期が不要です。
完了チェックと削除
import { useState } from 'react';
const initialItems = [
{ id: 1, title: 'JSXを読む', done: false },
{ id: 2, title: 'propsを渡す', done: true },
];
export default function App() {
const [items, setItems] = useState(initialItems);
function toggle(id) {
setItems(current => current.map(item =>
item.id === id ? { ...item, done: !item.done } : item
));
}
return (
<main>
<h1>チェックリスト</h1>
<p>{items.filter(item => item.done).length}件完了</p>
<ul>
{items.map(item => (
<li key={item.id}>
<label>
<input type="checkbox" checked={item.done} onChange={() => toggle(item.id)} />
{item.title}
</label>
<button type="button" onClick={() =>
setItems(current => current.filter(row => row.id !== item.id))
}>{item.title}を削除</button>
</li>
))}
</ul>
{items.length === 0 && <p>項目はありません。</p>}
</main>
);
}checkboxはcheckedで真偽値を渡します。具体的な入力の扱いは次のレッスンで確かめます。
TRY IT YOURSELF
一覧の項目を操作する
- 先頭の項目を完了にし、件数が増えることを確認する
- 先頭を削除し、残った行の内容とチェック状態が保たれることを確認する
- 全件削除して0件の表示を確認する
- setItems(current => [...current].reverse())を使う並び替えボタンを追加する
できたらOK:チェック・削除・並び替え後も、操作したIDと表示の状態が一致する
QUICK CHECK
理解を確かめよう
公式資料でもう少し詳しく
ここまで読めたら、ひとつ前進。