React.jsでWarning: Each child in a list should have a unique "key" prop.が発生した時の原因と対処法

![スクリーンショット 2022-09-27 22.26.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1812049/8f449dda-92b2-e3d1-d0d1-e51067276aff.png)
ReactやNext.jsで開発していると、スクショのようなwarningに遭遇したことあるかと思います。

## 原因
map関数内でhtmlタグをreturnする時に、一番上の要素にユニークなkeyを定義していないこと、もしくはkeyがユニークになってないことが原因です。
Reactで要素を一覧表示するときとかに、誰しも一度は発生するwarningではないのでしょうか。

### 具体的にこのようなコードの時に発生します。
##### １、keyを定義していない
```
const USER_LIST = [
    { id: 1, username: "hoge", age: 10 },
    { id: 2, username: "foo", age: 15 },
    { id: 3, username: "hoge", age: 21 },
    { id: 4, username: "react", age: 43 },
    { id: 5, username: "next", age: 5 },
  ];

 <ul>
    {USER_LIST.map((user, index) => (
      <li>
        <p>{user.username}</p>
        <p>{user.age.toString()}歳</p>
      </li>
    ))}
 </ul>
```

##### ２、keyがユニークになってない（同じ値のkeyがある）
```
 <ul>
    {USER_LIST.map((user, index) => (
      <li key={user.username}>
        <p>{user.username}</p>
        <p>{user.age.toString()}歳</p>
      </li>
    ))}
 </ul>
```
※ちなみにkeyがユニークになってない時はこういったwarningになります。
![スクリーンショット 2022-09-27 22.35.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1812049/c4cbcb7c-5298-de05-888a-d20c6eef266f.png)

## 解決方法
原因に書いてある通りユニークなkeyを付与してないことが問題なので、ユニークなkeyを挿れます。
```
 <ul>
    {USER_LIST.map((user, index) => (
      <li
        key={user.id} //←ユニークなkey
        style={{ display: "flex", justifyContent: "start" }}
      >
        <p>{user.username}です。</p>
        <p>現在{user.age.toString()}歳です</p>
      </li>
    ))}
 </ul>
```
![スクリーンショット 2022-09-28 1.37.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1812049/1128de9f-b14a-7678-0130-5e6777e87408.png)
無事表示されました！

## ここからが本題
上記の方法で基本的には解決できますのが、
もしもmap関数内でreturnするhtmlタグが複数の時だったり、複数のタグをreturnするが、divタグなどで一つに囲いたくないことがたまにあるかと思います。
```
 <ul>
    {USER_LIST.map((user, index) => (
      <>
        <li
          key={user.id}
          style={{ display: "flex", justifyContent: "start" }}
        >
          <p>{user.username}です。</p>
          <p>現在{user.age.toString()}歳です</p>
        </li>
        {user.age >= 20 && (
          <p style={{ color: "red", fontWeight: "bold" }}>
            このかたは成人です
          </p>
        )}
      </>
    ))}
 </ul>
```
今回のケースとしては、もしユーザーの年齢が20歳以上だったら赤文字で「このかたは成人です」と表示させたいです。
liタグには入れたくないので、上の階層にhtmlタグを用意しますが、設計上divタグを使いたくないので空タグを用意しました。
ですので現状、空タグの中には二つhtmlタグが挿れられてます。

##### この状態でconsoleを開くと、、、
![スクリーンショット 2022-09-28 1.46.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1812049/ad5b24a2-cda2-a33e-ce72-7c9d0d66da37.png)
エラーになってます。
解決方法を模索しました。

#### 検証１ 同じkeyを挿れる
新しく追加した特定の条件の時のみ表示されるpタグにも同様のkeyを挿れてみました。
liタグと同様にuser.idを挿れてみると、以前発生したような「同じkeyがあります」とエラーになってしまいましたので、これではないようです。

#### 検証２ 別のユニークなidを挿れる
次はuser.idとは別のユニークなidである、map関数の第二引数のindexを使いました。
再度consoleを開いてみると、、、
```
 <ul>
    {USER_LIST.map((user, index) => (
      <>
        <li
          key={user.id}
          style={{ display: "flex", justifyContent: "start" }}
        >
          <p>{user.username}です。</p>
          <p>現在{user.age.toString()}歳です</p>
        </li>
        {user.age >= 20 && (
          <p key={index} style={{ color: "red", fontWeight: "bold" }}>
            このかたは成人です
          </p>
        )}
      </>
    ))}
 </ul>
```
![スクリーンショット 2022-09-28 1.49.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1812049/ab8de900-9dfd-1ee1-8406-4f00fcd84447.png)
またエラーになってます。。

### 原因
原因は「map関数内でreturnするhtmlタグの一番上の要素にkeyを定義していない」からです。
今回だと一番上の要素は空タグなので反映されないだろと思われますが、どうやらエラーになってしまうようです。
もちろん空タグなのでkeyを定義することは不可能です。

### 解決方法
解決方法としては、空タグを使うのではなく「``React.Fragment``」を使用することです。
空タグではkeyを定義することが不可能でしたが、同様の機能をするReact.Fragmentに変えるとkeyを定義することができます。
公式の参考サイト ： https://ja.reactjs.org/docs/fragments.html
```
 <ul>
    {USER_LIST.map((user, index) => (
      <React.Fragment key={user.id}>
        <li style={{ display: "flex", justifyContent: "start" }}>
          <p>{user.username}です。</p>
          <p>現在{user.age.toString()}歳です</p>
        </li>
        {user.age >= 20 && (
          <p style={{ color: "red", fontWeight: "bold" }}>
            このかたは成人です
          </p>
        )}
      </React.Fragment>
    ))}
 </ul>
```
![スクリーンショット 2022-09-28 1.54.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1812049/b138b57b-40b9-a2a4-8b7c-083c0a89738a.png)
無事warningが消えて解決できました！！！

warningが一つあるだけでもconsole.logのエリアに結構大きく表示されてしまうので、極力解決していきたいですね