環境
- Node v18.0.6
- Next.js v12.1.6
- React v 18.1.0
ループ処理する
配列で与えられた場合
const array = ["apple", "banna", "pear"];
mapメソッドを使います。
return (
<>
{array.map((fruit) => {
return <div>{fruit}</div>;
})}
</>
);
一応は描画されますが、コンソールに「keyがありません」と警告が出ます。
ループ処理したReact要素にはkeyプロパティをつけると、Reactが差分レンダリングに活用してくれます。
keyは兄弟間で一意なものであればなんでもいいです。
この場合使えるのはfruit(フルーツの名前)か、配列のインデックスです。
今回はインデックスを使いますが、本当はあまり良くないです。後述。
return (
<>
{array.map((fruit, index) => {
return <div key={index}>{fruit}</div>;
})}
</>
);
オブジェクトで与えられた場合
const obj = { fruit1: "apple", fruit2: "banana", fruit3: "pear" };
Object.keys()でオブジェクトのキーを配列で取得し、その配列のmapメソッドを使います。
return (
<>
{Object.keys(obj).map((key) => {
return <div key={key}>{obj[key]}</div>;
})}
</>
);
配列の時と同様に、keyをつけます。今回はオブジェクトのキーがあるので、それを使いましょう。
return (
<>
{Object.keys(obj).map((key) => {
return <div key={key}>{obj[key]}</div>;
})}
</>
);
なぜインデックスをkeyにしないほうがいいのか
配列のある要素が常に同じインデックスを持っている保証がないからです。
今回のコードではただ配列を描画しましたが、実際にアプリを作る際には配列の内容が変化していく事が考えられます。
例えば「購入した果物のリスト」を描画したいなら、
購入した果物用の配列を用意して、ユーザーが購入するたびにそれを更新して...というふうになるでしょう。
新しい果物を配列の後ろに追加する分には問題ありませんが、前から追加したり、ソートしたりすると更新のたびに既存の要素のインデックスが変わってしまいます。つまりkeyが変わってしまいます。
Reactはkeyを頼りに差分レンダリングを行うので、これはバグに繋がります。
配列に変更がある可能性があるときはインデックスをkeyに使うのは避けるべきです。
逆に言うと、今回のサンプルコードの場合はインデックスでも十分です。
参考欄に載せたのZennの記事がとてもわかり易かったです。
参考