9
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

React学習ログ No.14

Posted at

React: splice() とイミュータビリティ(不変性)

概要

JavaScriptの splice() は配列から要素を削除・置換・追加できるメソッド
しかし、Reactのstate(状態)に対して直接使うと、バグの原因になる

1. splice() とは?

  • 機能: 配列の既存の要素を変更(削除、置換、追加)する
  • 構文: array.splice(index, deleteCount, item1, ..., itemX)
  • 最大の特徴: 呼び出した元の配列そのものを変更してしまう
// サンプルコード
const fruits = ['apple', 'banana', 'orange'];
fruits.splice(1, 1, 'grape'); // 1番目から1個削除し、'grape'を追加

console.log(fruits); // 結果: ['apple', 'grape', 'orange']
// 元の 'fruits' 配列自体が変わる

2. React (State) で splice() を直接使うとなぜダメなのか?

Reactは、stateが変更されたことを検知して、
コンポーネントを再レンダリング(再描画)する

この「変更検知」は、基本的にstateの参照が変わったかどうかで判断される

splice() は元の配列の参照を変えずに、中身だけを変更してしまう

// Reactコンポーネント内(悪い例)
const [items, setItems] = useState(['a', 'b', 'c']);

const handleRemoveItem = (index) => {
  // 悪い例:stateの配列を直接変更している
  items.splice(index, 1);
  setItems(items); // 参照が変わっていないので、Reactは変更を検知できない
};

// この結果、画面が再レンダリングされず、削除が反映されない(予期せぬ挙動をする)

結論: Reactにおいて、state(配列やオブジェクト)は
イミュータブル(不変)に扱うのが鉄則。stateを直接変更してはいけない

3. Reactでの正しい対処法(イミュータブルな操作)

元のstate配列を変更せず、新しい配列を作って setItems に渡す

A. 要素の削除: filter() を使用

filter() は、元の配列を変更せず、条件に合う要素だけで新しい配列を返す

// 良い例:filter を使用
const handleRemoveItem = (targetIndex) => {
  const newItems = items.filter((item, index) => {
    return index !== targetIndex;
  });
  setItems(newItems);
};

B. 要素の追加: スプレッド構文 (...) を使用

// 良い例:スプレッド構文で追加
const handleAddItem = (newItem) => {
  const newItems = [...items, newItem]; // 末尾に追加
  // const newItems = [newItem, ...items]; // 先頭に追加
  setItems(newItems);
};

C. 要素の置換(更新): map() を使用

map() も、元の配列を変更せず、新しい配列を返す

// 良い例:map で特定要素を更新
const handleUpdateItem = (targetIndex, updatedItem) => {
  const newItems = items.map((item, index) => {
    return index === targetIndex ? updatedItem : item;
  });
  setItems(newItems);
};

D. どうしても splice() を使いたい場合

必ずコピーしてから使用
ただし、filtermap を使う方がReact的で推奨される

// 非推奨ではないが、冗長
const handleRemoveItem = (targetIndex) => {
  const newItems = [...items]; // まず配列をコピーする
  newItems.splice(targetIndex, 1); // コピーした配列を変更
  setItems(newItems); // 新しい配列をセット
};
9
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?