発生した事象
Reactでコードを書いていた際、Warning: Each child in a list should have a unique “key” prop.
というエラーが発生しました。
このエラーは「各々のchildには必ずユニークなkeyの値を持つこと」という意味であり、多くの場合はkeyの値を設定することで解消することができます。
const items = [
{id: 1, title: "item1"},
{id: 2, title: "item2"},
{id: 3, title: "item3"},
];
return (
<div>
{items.map(elem => {
return(
{/* ここに値が一意に定まるkey値を設定しないとエラーになる */}
<div key={elem.id}>
<p>{elem.title}</p>
</div>
)
})}
</div>
);
ですが、今回遭遇したケースではkey値を設定しているのにも関わらずEach child in a list should have a unique “key” prop.
エラーが発生しました。
{/* solutionDataはデータベースから取得した値を配列化したもの */}
{solutionData.map((elem) => {
return (
<>
<div key={elem.id} id={elem.id}>
<div>
<div className="flex">
<p>{cdate(elem.created_at).format("YYYY-MM-DD")}</p>
<p>{elem.practice_category}</p>
</div>
<p>{elem.practice_text}</p>
</div>
<div>
{elem.video_id && (
<div className="px-2 py-4">
<iframe
id="player"
width="100%"
src={"https://www.youtube.com/embed/" + elem.video_id} //先ほど保存したvideoId
allowFullScreen
className="aspect-16/9"
/>
</div>
)}
</div>
</div>
</>
);
})};
原因
上記のサンプルではreturnの一番外側の要素がkey値を持っていないことが原因。
<></>
を使っている場合でもkeyはmapメソッドの一番外側で設定しないといけませんでした。
また、<></>
の中にkeyを設定してもエラーとなります。
key をフラグメントに渡したい場合は、<>...> 構文を使用することはできません。
対策
①mapメソッドの一番外側のdivタグにkeyを設定する
mapメソッドの内側が並列な<div>
で囲まれていない場合はこの方法が一番シンプルで分かりやすい。
先ほどの例で言うと以下のような形になる。
{solutionData.map((elem) => {
return (
{/* この箇所にあった<></>を削除。これでもHTML構造的にkeyは成立する */}
<div key={elem.id} id={elem.id}>
<div>
<div className="flex">
<p>{cdate(elem.created_at).format("YYYY-MM-DD")}</p>
<p>{elem.practice_category}</p>
</div>
<p>{elem.practice_text}</p>
</div>
<div>
{/* 動画が入る部分。今回の本筋に関係ないため省略 */}
</div>
</div>
);
})};
②<></>
を<Fragment></Fragment>
に変更する
React公式でも推奨されている方法。
<></>
となっている部分を明示的に<Fragment>
に書き直すことでkey値を設定することができる。
key値は<Fragment>
タグの内側に書く。
key: 明示的な 構文で宣言されたフラグメントは key を持つことができます。
'react' から Fragment を明示的にインポートし、... とレンダーしなければなりません。
<></>
の内側が並列なdivタグになっているような、<></>
を使わないと支障が出るケースで特に有効。
import { Fragment } from "react";
{solutionData.map((elem) => {
return (
{/* ここの空フラグメントをFragmentに変更する */}
<Fragment key={elem.id}>
<div id={elem.id}>
<div>
<div className="flex">
<p>{cdate(elem.created_at).format("YYYY-MM-DD")}</p>
<p>{elem.practice_category}</p>
</div>
<p>{elem.practice_text}</p>
</div>
<div>
{/* 動画が入る部分。今回の本筋に関係ないため省略 */}
</div>
</div>
</Fragment>
);
})};
①、②いずれかの方法を取れば「keyを設定しているのにエラーが出る」という現象を回避できるはずです。
最後に
今回発生したエラーは私の中でハマる頻度が多く、何回も繰り返す割に解決策が見つからないものでした。
同じようなエラーが発生した際に解決の糸口になれば幸いです。
参考文献・記事