🍎

reactでやりがちなkeyの間違った使い方

に公開

なぜkeyが必要なのか

keyがない状態はデスクトップ上のファイルに名前がないようなもので、ファイルを1番目、2番目と管理するようなものらしいです。
keyを設定することで並べ替えがあってもその項目を認識してそこだけ再レンダリングします。

もし設定していない場合はエラーが出ますが、このときには便宜的にインデックスを指定していると公式ドキュメントにありました。

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

ですが、この後書いているようにkeyにインデックスを指定するのはパフォーマンス低下やバグに繋がるのでエラーを表示しています。

key={index}がNGな理由

keyは要素が追加、削除された際に変更された要素だけ再レンダリングするために指定します。
そのため以下のNG例のようにkey={index}と指定すると、変更があった際にすべての要素を再レンダリングしてしまうので、パフォーマンスの低下につながります。

NG例

const items = ["apple", "banana", "orange"];
{items.map((item, index) => (
  <div key={index}>{item}</div>
))}

OK例

const items = [
  { id: "1", value: "apple" },
  { id: "2", value: "banana" },
  { id: "3", value: "orange" }
];
{items.map((item) => (
  <div key={item.id}>{item}</div>
))}

そのため、このようにitemsにidキーを追加してkey={item.id}と指定することで、再レンダリングが変更のあった要素だけになります。
同様の理由でkey={Math.random()}のようにするのもアンチパターンです。

二つのパターンを比較


再レンダリング以外に、バグが起きる可能性もあります。
この画像は二つのパターンを比較したものです。テキストボックスを追加するとkeyの値が変更され、インデックスを指定した方は入力した値の入っている箇所が変わっています。(左のkey=indexを見るとFooにFooが、BarにBarが入っているが、右を見るとBarにFooが、FooにBarが入っている)
動的な配列を使う場合は配列のidを指定するべきですね。

そのため、逆に言えば配列が固定である場合はOKだそうです。

const WEEKDAYS = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"];
{WEEKDAYS.map((day, index) => (
  <div key={index}>{day}</div>
))}

配列の並び替え、追加、削除が必ずないと言い切れる時は例外的にインデックスの指定でも可です。
ただ今は静的でも将来的に動的になる可能性がある配列には使わないほうが無難です。

NCDCエンジニアブログ

Discussion