フラグメントとは
下記のように、<>...</>
という構文を使うことで、ラッパー用のdiv
タグなどを使わずに要素をグループ化することができます。
<>
<Child />
<Child />
</>
このように要素をグループ化して、出力される DOM には影響を与えないタグのことをフラグメントといいます。
map
でレンダリングするコンポーネントには key
プロップスを渡す
React では配列の値に応じた内容のコンポーネントを繰り返し表示する際に、配列メソッドのmap
を使うことがよくあります。
<List>
{["アイテム1", "アイテム2", "アイテム3"].map((value) => {
return <ListItem key={value}>{value}</ListItem>;
})}
</List>
繰り返し処理によって生成するコンポーネントは、key
プロップスに一意の値を渡すことが推奨されています。
これを行わないとブラウザのコンソールに警告が表示されます。
<></>
(フラグメント)にkey
を渡すには
状況によっては、フラグメントでラップしたコンポーネントを繰り返し処理で生成することがあります。
しかし、<></>
にはプロップスを渡すことはできません。
実は<></>
という構文は、<React.Fragment>
というコンポーネントの省略記法であり、key
を渡すときはこの省略なしの記法で書いたフラグメントに渡す必要があります。
<dl>
{[
{ id: 0, title: "見出し1", content: "内容1" },
{ id: 1, title: "見出し2", content: "内容2" },
].map((item, index) => {
return (
<React.Fragment key={id.toString()}>
<dt>{item.title}</dt>
<dd>{item.content}</dd>
</React.Fragment>
);
})}
</dl>
このようにすることで、フラグメントでラップしたコンポーネントにkey
を渡すことができます。
最後になぜ繰り返し処理で生成するコンポーネントにはkey
を渡すことが推奨されるのかを説明します。
key の役割
仮想 DOM の仕組み
key の役割を理解するためには、まずは React の仮想 DOM の仕組みを知っておくと良いです。
まず、React では仮想 DOM を JavaScript オブジェクトとしてメモリ上に構築します。JavaScript オブジェクトの操作はブラウザの DOM 操作に比べて格段に低コストです。
そして、UI の状態が変化すると、React は全体の仮想 DOM ツリーを再構築します。
その後、新しい仮想 DOM ツリーと以前の仮想 DOM ツリーを比較して、特定された差分のみを実際の DOM に反映します。
React ではこのようなプロセスを行って、実際の DOM の更新を最小限にすることでパフォーマンスを最適化しているのです。
一意な key を渡す意味
前述した通り、React は UI の状態変化の前後で仮想 DOM の差分を特定することによって高パフォーマンスな描画を行います。
これを助けるために必要なのが、リストの各要素に一意な値を設定することなのです。
適切な key が提供されていると、React はリストの中の要素を一意に特定し、変更された要素だけを効率的に更新できます。
逆に、同じ key を持つコンポーネントは再利用されることがあるので、適切な key が渡されていないと、状態が意図しない形で引き継がれて再利用されてしまう可能性があるのです。
key
に index
を渡すのは推奨されていない
下記のように、key
に map
メソッドのコールバック関数の index
を渡すのは推奨されていません。
<dl>
{[
{ title: "見出し1", content: "内容1" },
{ title: "見出し2", content: "内容2" },
].map((item, index) => {
return (
<React.Fragment key={index}>
<dt>{item.title}</dt>
<dd>{item.content}</dd>
</React.Fragment>
);
})}
</dl>
なぜならば、index
は配列の要素の順番の数値であり、要素の順番が変われば key
の値も変わってしまうため、前述した key
の役割と反することになるからです。
多くの場合ではデータの id
を key
として渡すことになると思います。
index
を渡すのは、配列の順番に変更の可能性がない場合の最終手段と考えるのが良さそうです。
ちなみに、key
は兄弟要素の中で一意な値になっていれば十分なので、他のリストの要素と key
が重ならないようにする必要はありません。