React学習記録

【実例で学ぶ】Reactで配列のstateを更新する5つのパターン

yuya_react

はじめに

こんにちは、優也@月収100万を目指して月100時間勉強する男です。

前回までの記事で、TODOアプリを完成させました。その中で、配列のstateを追加・削除・更新する処理を実装しましたが、「なぜこの書き方なのか?」を詳しく解説していませんでした。

今回は、Reactで配列のstateを更新する方法について、5つのパターンに分けて解説します。TODOアプリで実装した処理を振り返りながら、配列操作の基本を身につけましょう。

なぜ特別な書き方が必要?

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

❌ これはダメ

const [items, setItems] = useState([1, 2, 3]);

// ❌ 直接変更
items.push(4);
items[0] = 10;

✅ 正しい方法

<em>// ✅ 新しい配列を作る</em>
setItems([...items, 4]);
setItems([10, ...items.slice(1)]);

理由

Reactは参照が変わったかどうかで再レンダリングを判断します。配列の中身を変更しても、配列自体の参照は変わらないため、Reactが変更を検知できません。

パターン1: 要素を追加する

配列の末尾に要素を追加する方法です。

スプレッド構文を使う

const [items, setItems] = useState([1, 2, 3]);

const addItem = () => {
  setItems([...items, 4]);
};

コードの説明

[...items, 4]
  • ...items: 既存の配列を展開
  • , 4: 新しい要素を追加
  • []で囲んで新しい配列を作成

結果: [1, 2, 3, 4]

TODOアプリでの実例

const addTask = () => {
  const newTask = {
    id: newId,
    taskName: inputTask,
    completed: false
  };

  setTasks([...tasks, newTask]);
};

先頭に追加する場合

setItems([4, ...items]);

結果: [4, 1, 2, 3]

パターン2: 要素を削除する

filterを使って、条件に合わない要素を除外します。

filterメソッドを使う

const [items, setItems] = useState([
  { id: 1, name: 'りんご' },
  { id: 2, name: 'バナナ' },
  { id: 3, name: 'オレンジ' }
]);

const deleteItem = (id) => {
  setItems(items.filter((item) => item.id !== id));
};

コードの説明

items.filter((item) => item.id !== id)
  • filter: 条件に合う要素だけを残す
  • item.id !== id: 削除対象以外を残す
  • 新しい配列が返される

TODOアプリでの実例

const deleteTask = (id) => {
  setTasks(tasks.filter((task) => task.id !== id));
};

インデックスで削除する場合

const deleteByIndex = (index) => {
  setItems(items.filter((_, i) => i !== index));
};

_は使わない変数を表す慣習的な書き方です。

パターン3: 要素を更新する

mapを使って、特定の要素だけを更新します。

mapメソッドを使う

const [items, setItems] = useState([
  { id: 1, name: 'りんご', price: 100 },
  { id: 2, name: 'バナナ', price: 80 },
  { id: 3, name: 'オレンジ', price: 120 }
]);

const updatePrice = (id, newPrice) => {
  setItems(
    items.map((item) =>
      item.id === id ? { ...item, price: newPrice } : item
    )
  );
};

コードの説明

items.map((item) =>
  item.id === id ? { ...item, price: newPrice } : item
)
  • map: すべての要素を処理
  • item.id === id: 対象の要素か判定
  • { ...item, price: newPrice }: 対象ならpriceを更新
  • : item: 対象外ならそのまま

TODOアプリでの実例

const completeTask = (id) => {
  setTasks(
    tasks.map((task) =>
      task.id === id ? { ...task, completed: true } : task
    )
  );
};

パターン4: 複数の要素を更新する

filterとmapを組み合わせることもできます。

条件に合う要素を一括更新

const [items, setItems] = useState([
  { id: 1, name: 'りんご', category: '果物', discount: false },
  { id: 2, name: 'バナナ', category: '果物', discount: false },
  { id: 3, name: 'にんじん', category: '野菜', discount: false }
]);

const applyDiscountToCategory = (category) => {
  setItems(
    items.map((item) =>
      item.category === category ? { ...item, discount: true } : item
    )
  );
};

「果物」カテゴリの商品すべてにdiscountフラグを付けることができます。

パターン5: 並び替え

配列を並び替える方法です。

sortを使う(注意が必要)

const [items, setItems] = useState([3, 1, 4, 1, 5]);

// ❌ これはダメ(元の配列を変更してしまう)
const sortItems = () => {
  items.sort();
  setItems(items);
};

// ✅ 正しい方法(新しい配列を作る)
const sortItems = () => {
  setItems([...items].sort());
};

コードの説明

[...items].sort()
  • [...items]: 配列をコピー
  • .sort(): コピーした配列をソート
  • 元の配列は変更されない

オブジェクトの配列をソート

const [items, setItems] = useState([
  { id: 3, name: 'オレンジ' },
  { id: 1, name: 'りんご' },
  { id: 2, name: 'バナナ' }
]);

// IDでソート
const sortById = () => {
  setItems([...items].sort((a, b) => a.id - b.id));
};

// 名前でソート
const sortByName = () => {
  setItems([...items].sort((a, b) => a.name.localeCompare(b.name)));
};

よくある間違い

❌ 間違い1: 直接pushを使う

// ❌ これはダメ
const addItem = () => {
  items.push(newItem);
  setItems(items);
};

// ✅ 正しい
const addItem = () => {
  setItems([...items, newItem]);
};

❌ 間違い2: インデックスで直接変更

// ❌ これはダメ
const updateItem = (index) => {
  items[index] = newValue;
  setItems(items);
};

// ✅ 正しい
const updateItem = (index) => {
  setItems(items.map((item, i) => (i === index ? newValue : item)));
};

❌ 間違い3: spliceを使う

// ❌ これはダメ
const deleteItem = (index) => {
  items.splice(index, 1);
  setItems(items);
};

// ✅ 正しい
const deleteItem = (index) => {
  setItems(items.filter((_, i) => i !== index));
};

まとめ

Reactで配列のstateを更新する5つのパターンを解説しました。

重要なポイント:

  • ✅ 配列を直接変更しない
  • ✅ 常に新しい配列を作る
  • ✅ スプレッド構文を活用
  • ✅ filter、mapで新しい配列を返す
  • ✅ sortは元の配列を変更するので注意

5つのパターン:

  1. 追加: [...items, newItem]
  2. 削除: items.filter((item) => item.id !== id)
  3. 更新: items.map((item) => item.id === id ? {...item, updated} : item)
  4. 一括更新: items.map()で条件に合う要素を更新
  5. 並び替え: [...items].sort()

これらのパターンを覚えれば、Reactでの配列操作はバッチリです!


この記事のシリーズ:

  1. 【React入門】未経験からReactを学んで最初のTODOアプリを作った話
  2. 【2025年版】Viteで始めるReact開発環境の構築方法
  3. 【React基礎】useStateとは?初心者向けに分かりやすく解説
  4. 【React】イベントハンドラの書き方完全ガイド
  5. 【React】map関数でリストをレンダリングする方法
  6. 【React入門】TODOアプリの作り方 – 前編
  7. 【React入門】TODOアプリの作り方 – 中編
  8. 【React入門】TODOアプリの作り方 – 後編
  9. 【実例で学ぶ】配列のstate更新パターン ← 今ここ
  10. 【React初心者が詰まった】エラー解決集(次回)

あとがき

月100時間の学習時間の中で、今月はReactに集中して取り組んでいます。Instagramでは、フリーランスとして月収100万円を目指す道のりを、リアルタイムで発信していきますので、ぜひフォローしてください!

Instagram: @hooded_yuya_100man

ABOUT ME
記事URLをコピーしました