👌

mapのkey propsにindexはアンチパターン(React)

2023/03/01に公開

map の key ってなに?

JavaScript の map()を使用して配列からコンポーネントをレンダリングする方法は下記で実装できます。

const people = ["john", "michel", "kim", "Andy"];

export default function List() {
  const listItems = people.map((person) => <li>{person}</li>);
  return <ul>{listItems}</ul>;
}

上のコードを実行するとリストが生成されるのですが、コンソールには、下のエラーが出ます。

Warning: Each child in a list should have a unique "key" prop.

エラーを解消するためには、配列に id を持たせ、リストのアイテムに key として id を渡せばいいです。

const people = [
  {
    id: 1,
    name: "john",
  },
  {
    id: 2,
    name: "michel",
  },
  {
    id: 3,
    name: "kim",
  },
  {
    id: 4,
    name: "Andy",
  },
];

export default function List() {
  const listItems = people.map((person) => (
    <li key={person.id}>{person.name}</li>
  ));
  return <ul>{listItems}</ul>;
}

なぜ key が必要なのか

デスクトップ上のファイルに名前がないと想像してください。
代わりに、最初のファイル、2 番目のファイルなどの順序で参照します。
慣れるかもしれませんが、一度ファイルを削除すると混乱します。
2 番目のファイルが 1 番目のファイルになり、3 番目のファイルが 2 番目のファイルになり、以降も同様です。

上記と同様に map で生成したリストの内容が削除されたり、追加されたりすると順番がずれてきます。

この問題を起きないようにするために、リストのアイテムに一意の ID として key を与えるのです。

https://robinpokorny.medium.com/index-as-a-key-is-an-anti-pattern-e0349aece318

なぜ index がダメなのか

key のエラーを解除するために下記のように書きたくなるかもしれませんが、実は anti-pattern です。
リストの要素が増えるたびに再レンダリングが走り、そのたびに index を再生成するため、アイテムごとに一意の id という訳には行かなくなってしまいます。

要素の並び順が変更される可能性がある場合、インデックスを key として使用することはお勧めしません。パフォーマンスに悪い影響を与え、コンポーネントの状態に問題を起こす可能性があります。
https://ja.reactjs.org/docs/lists-and-keys.html

export default function List() {
  const listItems = people.map((person, index) => (
    <li key={index}>{person}</li>
  ));
  return <ul>{listItems}</ul>;
}

じゃあどうすべきか

配列の中の一意のデータを使いましょう
一意のデータを作成しましょう

Key のルール

  • キーは兄弟要素間で一意でなければなりません。ただし、異なる配列の JSX ノードに同じキーを使用してもかまいません。
  • キーを変更してはなりません。変更すると、キーの目的が無効になります。レンダリング中にそれらを生成しないでください。

最後に

index を使っていけないというわけではなく、 配列の内容が絶対に変更されないことを十分に確認し最終手段として使うことができます。

React の公式にも書いてあります。

レンダーされる要素に安定した ID がない場合、最終手段として項目のインデックスを使うことができます

みなさんもバグの出ないコードを書きましょう

FYI
https://zenn.dev/luvmini511/articles/f7b22d93e9c182

GitHubで編集を提案

Discussion

ログインするとコメントできます