4
2

More than 1 year has passed since last update.

【React】map()関数のkeyは本当に重要ですよ!

Last updated at Posted at 2023-02-10

はじめに

Reactのコードを書いて動的なリストをmap()関数で表現するとき、下記のようなエラーが開発者ツールに出ることがあります。
image.png
内容を見ますと、リスト内の各childはユニークなkeyを持つべきだ。と書いてますね。
keyを入力しなくても問題なく動きますので、無視したり、気付けないことも場合もあると思います。
でも、keyを使わないと何かしら問題があるから、このエラーを出しているでしょうね。
なので、今回はkeyを使わないと何が起こるかについて説明したいと思います。

keyがないと何が起こるのか。

まず下記の簡単なinput要素をmap()関数で表すコードを書いてみました。

import { useState } from 'react'

const App = () => {
  const [inputValue, setInputValue] = useState('')
  const [list, setList] = useState([])

  const addToList = () => {
    setList((prevList) => {
      return [{ value: inputValue }, ...prevList]
    })
    setInputValue('')
  }

  return (
    <>
      <input
        value={inputValue}
        onChange={(e) => setInputValue(e.target.value)}
      />
      <button onClick={addToList}>追加</button>
      <ul>
        {list.map((item) => {
          return <li>{item.value}</li>
        })}
      </ul>
    </>
  )
}

export default App

inputされた値は下記のコードによって、<li>値</li>になり、リストに追加されます。

   <ul>
     {list.map((item) => {
       return <li>{item.value}</li>
     })}
   </ul>

でも、list要素を追加する際に、右側のhtmlタグを見ますとすべてのliタグが光ってしまいます。
ezgif.com-video-to-gif.gif
え?どういうこと?
すみません。説明不足でした。

Reactは画面の要素の変更前と変更後の差を比較して、変わった要素だけを変更してくれるので、非常に効率的ですが、
keyを入力しないと、変更前と変更後の比較ができない、つまり何がアップデートされた項目かがわからないので、すべてのliタグの要素をDOM上にアップデートしてしまうのです。

例え1000個のリスト項目があるとしたら、1個のリストを追加しただけで、1000個のリストを新たにアップデートしてしまうので、非常に効率の悪い作業になります。

keyにvalueを入れると

エラーになることを確認して、適当にkeyにvalueの値を入れてしまうこともあると思います。

   <ul>
     {list.map((item) => {
       return <li key={item.value}>{item.value}</li>
     })}
   </ul>

その時は、下のように、追加される要素だけが光るので、既存の要素はDOMにそのままの状態で新しい要素だけが追加されることがわかります。

ezgif.com-video-to-gif (1).gif

ですが、valueの値が重複してしまうと、keyの値も重複してしますので、挙動が変になる原因になります。
オレンジ項目があるのに、もう1つのオレンジを入力すると、オレンジをkeyとして持っている要素が2つになるため、2つの要素が光ってしまします。
これは、要素の削除や編集時に予想できない&エラーもでない不具合の原因になりますので注意が必要です。

ezgif.com-video-to-gif (2).gif

keyが重複するとき

こちらをご覧ください。keyが重複するとエラーをはきます。
image.png

内容としては、バナナというkeyはユニークではないといけない。そうではないと、複製されたり、アップデートに不具合がある可能性がある。になります。

下の動画を見ますと、みかんを入力した際に、バナナの項目もう1つ入力されてしまします。

ezgif.com-video-to-gif (5).gif

keyにindexを入れると

よくあるミスが、keyにmap()関数の第2引数のindexを入れることです。

   <ul>
     {list.map((item, index) => {
       return <li key={index}>{item.value}</li>
     })}
   </ul>

せっかくkeyを追加したのに、すべてのliタグが光りますね。

ezgif.com-video-to-gif (4).gif

indexは順番によって、値が変わるので、
下記の状態では、

  • りんご (index:0)
  • バナナ (index:1)

になり、みかんを追加することでindexの値が下記のように変わります。

  • みかん(index:0)
  • りんご (index:1)
  • バナナ (index:2)

つまり、keyにindexを入れてしまうと、要素の追加及び削除の際にindexの値が変わるのでkeyの値も変わることで、
Reactはどの要素が既存の要素かがわからなくなり(すべての要素が変更したと認識)、すべての要素がアップデートされてしまいます。
公式文書でもできる限りindexをkeyの値として使わないことを推薦すると書いています。

解決策

解決策としては、ユニークな値をkeyの値として入れてあげることです。
サーバーサイドからデータを持ってくる場合はidの値が存在することが多いので便利でしょう。
そうではない場合は、ライブラリのuuidをimportしてkeyの値として入れてあげる方法があります。

終わりに

簡単な内容でしたが、結構性能のためには重要な知識だと思いますので、ぜひ覚えていただきたいです。
以上です。ありがとうございました。

4
2
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
4
2