モダンJavaScriptの基礎から始める挫折しないためのReact入門 60日コース | Stateを使いこなす - DAY 27:Stateから削除

React 60日で身につけるReact
スポンサーリンク
スポンサーリンク
  1. DAY 27:Stateから削除 前半 ― 「消す」という操作でState更新の本質をつかむ
  2. filter()とは何か ― 「残したいものだけを集める」ための道具
    1. filter()の基本的なイメージ
  3. IDを使う ― 「どの要素を削除するか」を特定するための鍵
    1. なぜIDが必要なのか
    2. IDを使った削除のイメージ
  4. 削除ボタン ― 「ユーザーの操作」を削除処理につなぐ
    1. 削除ボタンを1行ごとに配置する
    2. onClickでIDを渡す
  5. State更新 ― 「削除」はStateを書き換えるのではなく“置き換える”
    1. Stateを直接変更しないという大原則
    2. 正しいState更新の書き方
  6. 練習用テンプレート:DAY 27 前半版「削除機能付き買い物リスト」
  7. DAY 27 前半のまとめ
  8. DAY 27:Stateから削除 中盤 ― 「安全で拡張しやすい削除」を身につける
  9. filter()を「削除専用の道具」として意識する
    1. 「消したいもの」ではなく「残したいもの」を考える
  10. IDを「削除の鍵」として設計する
    1. indexではなくIDを使う理由
    2. IDを使った安全な削除
  11. 削除ボタンを「State更新のトリガー」として意識する
    1. ボタンは「イベントの入り口」
    2. 無名関数でIDを渡す理由
  12. State更新を「置き換え」として理解する
    1. 「書き換え」ではなく「新しい値に置き換える」
    2. 正しいState更新の形
  13. 練習用テンプレート:DAY 27 中盤版「削除機能付き買い物リスト」
  14. DAY 27 中盤のまとめ
  15. DAY 27:Stateから削除(後半)― 「削除」を実用レベルに仕上げる
  16. filter()を「削除の標準形」として定着させる
    1. 削除の基本形をもう一度確認する
    2. 条件を増やしても考え方は同じ
  17. ID設計を「拡張前提」で考える
    1. 単なる連番ではなく「意味のあるID」にする
    2. まずは「IDは必ず持つ」を習慣にする
  18. 削除ボタンを「ユーザー体験」とセットで考える
    1. 単なる“消すボタン”から一歩進める
  19. State更新を「予測可能なもの」にする
    1. 削除後のStateを頭の中でイメージできるか
    2. 「直接いじる」と「置き換える」の違いをもう一度
  20. 練習用テンプレート:DAY 27 後半版「削除+確認付き買い物リスト」
  21. DAY 27 後半のまとめ

DAY 27:Stateから削除 前半 ― 「消す」という操作でState更新の本質をつかむ

DAY 27では、これまで追加してきたStateから 「削除する」 ことにフォーカスして学習していきます。 Reactアプリでは「追加」と同じくらい「削除」が頻繁に登場し、ここをきちんと理解しておくと、実用的なUIを自信を持って作れるようになります。

前半の学習項目は次の4つです。

  • filter()
  • ID
  • 削除ボタン
  • State更新

これらを、買い物リストを題材にしながらステップバイステップでかみ砕いていきます。

filter()とは何か ― 「残したいものだけを集める」ための道具

filter()の基本的なイメージ

まずは、JavaScriptの filter() メソッドから整理します。 filter() は、「配列の中から条件に合うものだけを残して、新しい配列を作る」 メソッドです。

シンプルな例から見てみます。

const numbers = [1, 2, 3, 4, 5];

const evenNumbers = numbers.filter((n) => n % 2 === 0);

console.log(evenNumbers); // [2, 4]
JavaScript

ここで起きていることは、

  • numbers という元の配列はそのまま
  • filter() に渡した関数が true を返した要素だけを残した 新しい配列 を作る
  • 元の配列 numbers は変更されない

という流れです。

重要ポイント:

  • filter() は「元の配列を壊さず、新しい配列を作る」メソッドです。
  • ReactのState更新では、「元のStateを直接変更しない」ことが非常に重要なので、filter() は削除処理と相性が抜群です。

IDを使う ― 「どの要素を削除するか」を特定するための鍵

なぜIDが必要なのか

削除したい要素を特定するには、「どれを消すか」を識別するための ID が必要になります。

買い物リストの1件分のデータを、次のようなオブジェクトで表現しているとします。

const item = {
  id: 1,
  name: "牛乳",
  bought: false,
};
JavaScript

このとき、

  • id: そのアイテムを一意に識別するための番号
  • name: 商品名
  • bought: 購入済みフラグ

という役割を持っています。

削除したいアイテムを指定するときは、「この id のものを消したい」という形で考えます。

IDを使った削除のイメージ

例えば、「IDが3のアイテムを削除したい」とします。

const items = [
  { id: 1, name: "牛乳" },
  { id: 2, name: "パン" },
  { id: 3, name: "卵" },
];

const idToDelete = 3;

const newItems = items.filter((item) => item.id !== idToDelete);

console.log(newItems);
// [
//   { id: 1, name: "牛乳" },
//   { id: 2, name: "パン" }
// ]
JavaScript

ここでのポイントは、

  • 「削除したいIDのもの」ではなく、 「削除したくないもの」だけを残す という発想で書いていること
  • item.id !== idToDelete という条件で、 「IDが一致しないものだけ」を残していること
  • 結果として、「IDが3のものだけが消えた新しい配列」ができていること

です。

削除ボタン ― 「ユーザーの操作」を削除処理につなぐ

削除ボタンを1行ごとに配置する

Reactコンポーネントの中で、買い物リストを表示している部分を考えます。

<ul>
  {items.map((item) => (
    <li key={item.id}>
      {item.name}
      <button>削除</button>
    </li>
  ))}
</ul>
JSX

このままだと、削除ボタンを押しても何も起きません。 ここに「削除処理」を紐づけていきます。

onClickでIDを渡す

削除処理を行う関数を用意します。

const handleDeleteItem = (idToDelete) => {
  setItems((prevItems) =>
    prevItems.filter((item) => item.id !== idToDelete)
  );
};
JSX

そして、ボタンの onClick でこの関数を呼び出します。

<ul>
  {items.map((item) => (
    <li key={item.id}>
      {item.name}
      <button onClick={() => handleDeleteItem(item.id)}>削除</button>
    </li>
  ))}
</ul>
JSX

ここで起きていることは、

  • ユーザーが「削除」ボタンをクリックする
  • onClick={() => handleDeleteItem(item.id)} が実行される
  • その行の item.idhandleDeleteItem に渡される
  • filter() によって、そのIDのアイテムだけが除かれた新しい配列が作られる
  • setItems によってStateが更新され、画面が再描画される

という流れです。

重要ポイント:

  • 削除ボタンは「どのアイテムを削除するか」という情報(ID)を持っている必要があります。
  • onClick={() => handleDeleteItem(item.id)} のように、 無名関数の中でIDを渡す形がよく使われます。

State更新 ― 「削除」はStateを書き換えるのではなく“置き換える”

Stateを直接変更しないという大原則

Reactでは、Stateを直接変更してはいけません。

例えば、次のようなコードはNGです。

// ❌ やってはいけない例
const handleDeleteItem = (idToDelete) => {
  items = items.filter((item) => item.id !== idToDelete);
};
JSX

理由は、

  • Reactは「Stateが変わったかどうか」を、 setState(ここでは setItems)が呼ばれたかどうかで判断するから
  • 直接変数を書き換えても、Reactはそれを検知できず、画面が更新されないから

です。

正しいState更新の書き方

正しい書き方は、必ず setItems を使って 新しい配列 を渡すことです。

const handleDeleteItem = (idToDelete) => {
  setItems((prevItems) =>
    prevItems.filter((item) => item.id !== idToDelete)
  );
};
JSX

ここでのポイントは、

  • prevItems は「今のStateの値」を表す引数
  • filter() で「削除したいID以外の要素だけを残した新しい配列」を作る
  • その新しい配列を setItems に渡すことで、Stateを更新している

ということです。

この形が、Reactにおける「削除」の基本パターンになります。

練習用テンプレート:DAY 27 前半版「削除機能付き買い物リスト」

最後に、DAY 27前半の学習項目をすべて含んだ、 シンプルな削除機能付き買い物リストのテンプレートを示します。

import { useState } from "react";

function ShoppingList() {
  const [itemName, setItemName] = useState("");
  const [items, setItems] = useState([]);
  const [nextId, setNextId] = useState(1);

  const handleAddItem = () => {
    const trimmed = itemName.trim();
    if (trimmed === "") {
      return;
    }

    const newItem = {
      id: nextId,
      name: trimmed,
    };

    setItems((prevItems) => [...prevItems, newItem]);
    setNextId((prevId) => prevId + 1);
    setItemName("");
  };

  const handleDeleteItem = (idToDelete) => {
    setItems((prevItems) =>
      prevItems.filter((item) => item.id !== idToDelete)
    );
  };

  return (
    <div>
      <h2>買い物リスト(Stateから削除 前半)</h2>

      <input
        type="text"
        value={itemName}
        onChange={(e) => setItemName(e.target.value)}
        placeholder="商品名を入力してください"
      />
      <button onClick={handleAddItem}>追加</button>

      <ul style={{ marginTop: "8px" }}>
        {items.map((item) => (
          <li key={item.id}>
            {item.name}
            <button
              style={{ marginLeft: "8px" }}
              onClick={() => handleDeleteItem(item.id)}
            >
              削除
            </button>
          </li>
        ))}
      </ul>
    </div>
  );
}

export default ShoppingList;
JSX

このコードの中には、

  • filter():削除したいID以外の要素だけを残した新しい配列を作る
  • ID:どのアイテムを削除するかを特定するための識別子
  • 削除ボタン:ユーザー操作から削除処理へIDを渡す役割
  • State更新setItems に新しい配列を渡すことで、Reactに「削除された」ことを伝える

というDAY 27前半の学習項目が、すべて自然な形で含まれています。

DAY 27 前半のまとめ

DAY 27前半で押さえてほしいのは、次のポイントです。

  • filter() は「残したいものだけを集めた新しい配列」を作るためのメソッドであり、削除処理と相性が良いこと
  • IDは「どの要素を削除するか」を特定するための鍵であり、item.id !== idToDelete という形で削除対象を決めること
  • 削除ボタンは、onClick={() => handleDeleteItem(item.id)} のようにして「IDを削除関数に渡す」役割を持つこと
  • State更新は、必ず setItems新しい配列 を渡す形で行い、元の配列を直接変更しないこと

この削除のパターンは、買い物リストだけでなく、

  • タスク管理アプリ
  • ユーザー一覧
  • コメント一覧

など、あらゆる「一覧から1件を消す」場面でそのまま使えます。 中盤・後半では、この削除パターンをさらに発展させて、 複数条件での削除や、確認ダイアログ、セキュリティ的な観点も含めて深掘りしていきます。


DAY 27:Stateから削除 中盤 ― 「安全で拡張しやすい削除」を身につける

DAY 27の中盤では、前半で学んだ「削除の基本パターン」を、 より安全に・拡張しやすく・実務に近い形に育てていきます。

学習項目は同じく、

  • filter()
  • ID
  • 削除ボタン
  • State更新

ですが、ここでは「なんとなく動く削除」から一歩進んで、 「安心して使える削除」 を目指していきます。

filter()を「削除専用の道具」として意識する

「消したいもの」ではなく「残したいもの」を考える

削除処理を書くとき、多くの人が最初にこう考えます。

「このアイテムを消したい」

しかし、filter() を使うときの発想は少し違います。

「このアイテム 以外 を残したい」

この発想の違いが、コードの書き方にそのまま現れます。

const handleDeleteItem = (idToDelete) => {
  setItems((prevItems) =>
    prevItems.filter((item) => item.id !== idToDelete)
  );
};
JSX

ここでは、

  • item.id !== idToDelete → 「削除したいID ではない アイテムだけを残す」
  • 結果として、「削除したいアイテムだけが消えた新しい配列」ができる

という形になっています。

重要ポイント:

  • filter() は「残したいものだけを集める」メソッドです。
  • 削除処理を書くときは、「何を消すか」ではなく「何を残すか」を考えると、コードが自然になります。

IDを「削除の鍵」として設計する

indexではなくIDを使う理由

削除対象を特定するためには「鍵」が必要です。 それが ID です。

一方で、mapindex をそのまま使いたくなることもあります。

// ❌ よくある危険な書き方
{items.map((item, index) => (
  <li key={index}>
    {item.name}
    <button onClick={() => handleDeleteItem(index)}>削除</button>
  </li>
))}
JSX

一見動きそうですが、これは中盤の段階で避けたい書き方です。

理由は、

  • 並び替えや途中削除が入ると、「index」と「本来消したいアイテム」がずれてしまう可能性がある
  • Reactの再レンダリング時に、key がindexだと要素の再利用が誤って行われることがある

など、後からバグの温床になりやすいからです。

IDを使った安全な削除

IDを使うと、削除対象を安定して特定できます。

const handleDeleteItem = (idToDelete) => {
  setItems((prevItems) =>
    prevItems.filter((item) => item.id !== idToDelete)
  );
};

<ul>
  {items.map((item) => (
    <li key={item.id}>
      {item.name}
      <button onClick={() => handleDeleteItem(item.id)}>削除</button>
    </li>
  ))}
</ul>
JSX

ここが中盤の大事な一歩:

  • 「削除対象を特定する鍵として、IDを必ず持たせる」
  • key にも id を使うことで、Reactの内部処理とも整合性が取れる」

この設計を習慣にしておくと、後から機能を増やしても破綻しにくくなります。

削除ボタンを「State更新のトリガー」として意識する

ボタンは「イベントの入り口」

削除ボタンは、ただの見た目ではなく、 「ユーザー操作 → State更新」への入り口です。

<button onClick={() => handleDeleteItem(item.id)}>削除</button>
JSX

ここで起きていることは、

  1. ユーザーが「削除」ボタンをクリックする
  2. 無名関数 () => handleDeleteItem(item.id) が実行される
  3. その行の item.idhandleDeleteItem に渡される
  4. filter() によって、そのIDのアイテムだけが除かれた新しい配列が作られる
  5. setItems によってStateが更新され、画面が再描画される

という流れです。

無名関数でIDを渡す理由

なぜ onClick={handleDeleteItem(item.id)} ではなく、 onClick={() => handleDeleteItem(item.id)} と書くのでしょうか。

// ❌ 間違った書き方
<button onClick={handleDeleteItem(item.id)}>削除</button>
JSX

この書き方だと、

  • コンポーネントが描画されるタイミングで handleDeleteItem(item.id) が実行されてしまう
  • クリックする前に削除が起きてしまう

という問題があります。

正しい書き方は、「クリックされたときに実行する関数」を渡す形です。

<button onClick={() => handleDeleteItem(item.id)}>削除</button>
JSX

重要ポイント:

  • onClick には「関数そのもの」を渡す必要があります。
  • 無名関数 () => ... の中でIDを渡すことで、 「クリックされたときにだけ削除処理が走る」ようになります。

State更新を「置き換え」として理解する

「書き換え」ではなく「新しい値に置き換える」

ReactのState更新は、「書き換え」ではなく 「置き換え」 です。

NGな例から見てみます。

// ❌ やってはいけない例
const handleDeleteItem = (idToDelete) => {
  items = items.filter((item) => item.id !== idToDelete);
};
JSX

このコードは、

  • 変数 items を直接書き換えているだけで、
  • Reactに「Stateが変わった」と伝えていません。

その結果、

  • 画面が更新されない
  • 状態と表示がズレる

という問題が起きます。

正しいState更新の形

正しい形は、必ず setItems を使って 新しい配列 を渡すことです。

const handleDeleteItem = (idToDelete) => {
  setItems((prevItems) =>
    prevItems.filter((item) => item.id !== idToDelete)
  );
};
JSX

ここでの流れは、

  1. Reactが「今のState」を prevItems として渡す
  2. filter() で「削除したいID以外の要素だけを残した新しい配列」を作る
  3. その新しい配列を setItems に渡す
  4. Reactが「Stateが変わった」と認識し、再レンダリングする

というものです。

中盤で意識したい本質:

State更新とは、「元の値を直接いじること」ではなく、 「新しい値を作って、丸ごと置き換えること」である。

この感覚が身につくと、 追加・削除・更新のすべてが同じ軸で理解できるようになります。

練習用テンプレート:DAY 27 中盤版「削除機能付き買い物リスト」

中盤の内容をすべて含んだ、 削除機能付き買い物リストのテンプレートを示します。

import { useState } from "react";

function ShoppingList() {
  const [itemName, setItemName] = useState("");
  const [items, setItems] = useState([]);
  const [nextId, setNextId] = useState(1);

  const handleAddItem = () => {
    const trimmed = itemName.trim();
    if (trimmed === "") {
      return;
    }

    const newItem = {
      id: nextId,
      name: trimmed,
    };

    setItems((prevItems) => [...prevItems, newItem]);
    setNextId((prevId) => prevId + 1);
    setItemName("");
  };

  const handleDeleteItem = (idToDelete) => {
    setItems((prevItems) =>
      prevItems.filter((item) => item.id !== idToDelete)
    );
  };

  return (
    <div>
      <h2>買い物リスト(Stateから削除 中盤)</h2>

      <input
        type="text"
        value={itemName}
        onChange={(e) => setItemName(e.target.value)}
        placeholder="商品名を入力してください"
      />
      <button onClick={handleAddItem}>追加</button>

      <ul style={{ marginTop: "8px" }}>
        {items.map((item) => (
          <li key={item.id}>
            {item.name}
            <button
              style={{ marginLeft: "8px" }}
              onClick={() => handleDeleteItem(item.id)}
            >
              削除
            </button>
          </li>
        ))}
      </ul>
    </div>
  );
}

export default ShoppingList;
JSX

このテンプレートの中には、

  • filter():削除したいID以外の要素だけを残した新しい配列を作る
  • ID:削除対象を特定するための鍵として、item.id を利用する
  • 削除ボタンonClick={() => handleDeleteItem(item.id)} で、ユーザー操作から削除処理へIDを渡す
  • State更新setItems に新しい配列を渡すことで、Reactに「削除された」ことを伝える

というDAY 27中盤の学習項目が、すべて自然な形で含まれています。

DAY 27 中盤のまとめ

DAY 27中盤で身につけてほしいのは、次の感覚です。

  • filter() は「削除したいものを消す」のではなく、「残したいものだけを集める」ための道具である
  • IDは「削除対象を安全に特定するための鍵」であり、indexではなくIDを使うことで、並び替えや削除にも強い設計になる
  • 削除ボタンは「ユーザー操作 → State更新」の入り口であり、onClick には「関数そのもの」を渡す必要がある
  • State更新は「書き換え」ではなく「新しい値への置き換え」であり、setItems に新しい配列を渡す形が基本になる

この削除パターンは、買い物リストだけでなく、

  • タスク管理
  • ユーザー一覧
  • コメント削除

など、あらゆる「一覧から1件を消す」場面でそのまま使えます。

後半では、この削除パターンをさらに発展させて、 確認ダイアログや複数削除、より複雑な条件での削除などにも応用していきます。


DAY 27:Stateから削除(後半)― 「削除」を実用レベルに仕上げる

DAY 27の後半では、前半・中盤で学んだ削除のパターンを、 実際のアプリでそのまま使えるレベルに仕上げていきます。

テーマは変わらず「買い物リスト」ですが、ここでは次の4つを意識して深掘りします。

  • filter() を“削除のための標準ツール”として使いこなす
  • ID設計を「後から機能追加しても壊れない」ように考える
  • 削除ボタンを「ユーザー体験」とセットで設計する
  • State更新を「安全で予測可能なもの」にする

filter()を「削除の標準形」として定着させる

削除の基本形をもう一度確認する

削除の基本形は、次の1行に集約されます。

setItems((prevItems) =>
  prevItems.filter((item) => item.id !== idToDelete)
);
JSX

ここには、Reactで削除を行うための重要な要素がすべて入っています。

  • prevItems 今のState(現在の買い物リスト)です。
  • filter((item) => item.id !== idToDelete) 削除したいIDと一致しないものだけを残した新しい配列を作っています。
  • setItems(...) 新しい配列をStateとして保存し、Reactに「状態が変わった」と伝えています。

この形を「削除の標準形」として、頭と手に刻んでおくと、 どんな一覧でも同じパターンで削除を実装できるようになります。

条件を増やしても考え方は同じ

例えば、「購入済みのものだけ削除する」など、条件が増えても考え方は同じです。

const handleDeleteBoughtItems = () => {
  setItems((prevItems) =>
    prevItems.filter((item) => item.bought === false)
  );
};
JSX

ここでも、

  • 「残したいもの(購入していないもの)だけを集める」
  • 元の配列は直接変更せず、新しい配列を作る

という基本は変わりません。

ID設計を「拡張前提」で考える

単なる連番ではなく「意味のあるID」にする

これまで nextId を使った連番IDを使ってきました。

const [nextId, setNextId] = useState(1);

const newItem = {
  id: nextId,
  name: trimmed,
  bought: false,
};
JSX

連番IDはシンプルで分かりやすく、学習には最適です。 ただ、後半では「ID設計」を少しだけ意識してみます。

例えば、将来こういう機能を追加したくなるかもしれません。

  • サーバーと連携して、買い物リストを保存する
  • ユーザーごとに別のリストを持つ
  • 他の画面から同じアイテムを参照する

そのとき、IDは「アプリ全体で一意」であることが望ましくなります。

まずは「IDは必ず持つ」を習慣にする

今の段階では、複雑なID生成はまだ必要ありません。 大事なのは、

「一覧の1件には必ずIDを持たせる」

という習慣です。

この習慣があるだけで、

  • 削除
  • 更新
  • 詳細表示

などの機能を追加するときに、 「どのアイテムを対象にするか」を迷わずに済みます。

削除ボタンを「ユーザー体験」とセットで考える

単なる“消すボタン”から一歩進める

削除ボタンは、ただ「消す」だけではなく、 ユーザーが安心して操作できるかどうかにも関わります。

例えば、次のような改善が考えられます。

  • 誤クリックを防ぐために、削除ボタンを少し小さくする
  • 購入済みアイテムだけに削除ボタンを出す
  • 削除前に確認メッセージを出す

ここでは、確認メッセージを出す簡単な例を見てみます。

const handleDeleteItem = (idToDelete) => {
  const ok = window.confirm("本当に削除しますか?");
  if (!ok) return;

  setItems((prevItems) =>
    prevItems.filter((item) => item.id !== idToDelete)
  );
};
JSX

表示側は同じです。

<ul>
  {items.map((item) => (
    <li key={item.id}>
      {item.name}
      <button onClick={() => handleDeleteItem(item.id)}>削除</button>
    </li>
  ))}
</ul>
JSX

ここで意識したいこと:

  • 削除は「取り返しのつかない操作」になりがちなので、 ユーザーに一度確認するだけでも安心感が増すこと
  • 確認メッセージを挟んでも、削除の本質的なロジックは変わらないこと (filter+ID+State更新の形はそのまま)

State更新を「予測可能なもの」にする

削除後のStateを頭の中でイメージできるか

削除処理を書いたときに、 「この操作の後、Stateはどういう形になっているか」 を 頭の中でイメージできることが大事です。

例えば、次のようなStateがあったとします。

items = [
  { id: 1, name: "牛乳" },
  { id: 2, name: "パン" },
  { id: 3, name: "卵" },
];
JavaScript

ここで handleDeleteItem(2) を呼び出すと、 削除後のStateはこうなるはずです。

[
  { id: 1, name: "牛乳" },
  { id: 3, name: "卵" },
]
JavaScript

このイメージを持ったうえで、コードを読むと、

setItems((prevItems) =>
  prevItems.filter((item) => item.id !== idToDelete)
);
JSX

が、

  • 「IDが2のものだけを取り除いた新しい配列を作っている」
  • 「その新しい配列をStateとして保存している」

という意味だと、自然に理解できます。

「直接いじる」と「置き換える」の違いをもう一度

NGな例と比較してみます。

// ❌ NG例
const handleDeleteItem = (idToDelete) => {
  items.splice(
    items.findIndex((item) => item.id === idToDelete),
    1
  );
};
JSX

このコードは、

  • items を直接変更している
  • Reactに「Stateが変わった」と伝えていない

という問題があります。

一方、正しい例では、

const handleDeleteItem = (idToDelete) => {
  setItems((prevItems) =>
    prevItems.filter((item) => item.id !== idToDelete)
  );
};
JSX
  • 元の配列は直接触らず、新しい配列を作る
  • setItems によってReactに変更を伝える

という形になっています。

ここがReactのState更新の本質です。

練習用テンプレート:DAY 27 後半版「削除+確認付き買い物リスト」

DAY 27後半の内容をまとめたテンプレートを示します。

import { useState } from "react";

function ShoppingList() {
  const [itemName, setItemName] = useState("");
  const [items, setItems] = useState([]);
  const [nextId, setNextId] = useState(1);

  const handleAddItem = () => {
    const trimmed = itemName.trim();
    if (trimmed === "") {
      return;
    }

    const newItem = {
      id: nextId,
      name: trimmed,
    };

    setItems((prevItems) => [...prevItems, newItem]);
    setNextId((prevId) => prevId + 1);
    setItemName("");
  };

  const handleDeleteItem = (idToDelete) => {
    const ok = window.confirm("本当に削除しますか?");
    if (!ok) return;

    setItems((prevItems) =>
      prevItems.filter((item) => item.id !== idToDelete)
    );
  };

  return (
    <div>
      <h2>買い物リスト(Stateから削除 後半)</h2>

      <input
        type="text"
        value={itemName}
        onChange={(e) => setItemName(e.target.value)}
        placeholder="商品名を入力してください"
      />
      <button onClick={handleAddItem}>追加</button>

      <ul style={{ marginTop: "8px" }}>
        {items.map((item) => (
          <li key={item.id}>
            {item.name}
            <button
              style={{ marginLeft: "8px" }}
              onClick={() => handleDeleteItem(item.id)}
            >
              削除
            </button>
          </li>
        ))}
      </ul>
    </div>
  );
}

export default ShoppingList;
JSX

このテンプレートには、

  • filter():削除したいID以外の要素だけを残した新しい配列を作る
  • ID:削除対象を安全に特定するための鍵として item.id を利用する
  • 削除ボタンonClick={() => handleDeleteItem(item.id)} で、ユーザー操作から削除処理へIDを渡す
  • State更新setItems に新しい配列を渡すことで、Reactに「削除された」ことを伝える

というDAY 27後半の学習項目が、すべて含まれています。

DAY 27 後半のまとめ

DAY 27後半で定着させたいのは、次の感覚です。

  • filter() は「削除したいものを消す」のではなく、「残したいものだけを集める」ための標準ツールである
  • IDは「削除対象を安全に特定するための鍵」であり、indexではなくIDを使うことで、拡張に強い設計になる
  • 削除ボタンは「ユーザー操作 → State更新」の入り口であり、必要に応じて確認メッセージなどのユーザー体験も組み込める
  • State更新は「直接いじる」のではなく、「新しい値に置き換える」ことであり、setItems に新しい配列を渡す形が基本になる

この削除パターンが身につくと、 タスク管理・ユーザー一覧・コメント削除など、 あらゆる「一覧から1件を消す」機能を、 落ち着いて・安全に・自信を持って実装できるようになります。

タイトルとURLをコピーしました