Reactを使って複数の要素をリストとしてレンダーするとき、map()メソッドなどを使って以下のように書いたことがある方は多いと思います。
const items = ['りんご', 'みかん', 'ぶどう'];
function FruitList() {
return (
<ul>
{items.map((item) => {
return <li>{item}</li>;
})}
</ul>
);
}
このとき、コンソール上で警告が表示されることがあります。
Warning: Each child in a list should have a unique "key" prop.
この警告が示すとおり、React ではリストを描画する要素(子要素)にはユニークな「key」プロップを指定しなければなりません。では、なぜキーが必要なのでしょうか? 本記事では、キーが必要な背景と、どのように運用すれば良いかを解説します。
なぜキーが必要なのか?
1. 要素の差分を特定するため
React は仮想DOM(Virtual DOM)を用いてUIの差分更新を行っています。リストの各要素をレンダーする際、どの要素がどのデータに対応するかを判別するためにキーを使います。
要素を更新するとき
要素の追加や削除が起きたとき
これらの場合に、「どの要素が変更されたのか」を正しく特定するためには、**一意なキー(key)**が重要です。
2. パフォーマンス最適化
React はキーを使ってリスト内の要素が入れ替わったかどうかを高速に判断できます。
キーが正しく設定されていないと、React は最悪の場合、リスト内の要素を1つずつ「差分があるか」を再計算しなければなりません。
キーが正しく設定されていると、React はキーを手がかりに要素の移動・更新をすぐに把握でき、差分計算のパフォーマンスを最適化できるのです。
キー指定のベストプラクティス
1. ユニークなIDを使う
リストがAPIから取得したデータやDBに格納されているデータなど「一意のIDを持つ」場合、そのIDをキーに使うのが最適です。
const users = [
{ id: 1, name: '太郎' },
{ id: 2, name: '花子' },
{ id: 3, name: '次郎' },
];
function UserList() {
return (
<ul>
{users.map((user) => (
<li key={user.id}>{user.name}</li>
))}
</ul>
);
}
user.id はデータを一意に特定できるので、リストの順序が変わっても、React が正しく差分を把握できます。
2. インデックス(配列の位置)をキーにしない
配列のindexをキーとして使うことは推奨されません。
リストの並びが変更される場合(要素を並び替えたり、途中で追加・削除されたりする場合)に、同じインデックスでも別の要素を指すことがあり、React が正しい要素の対応関係を保てなくなる。
これにより、バグが発生したり、コンポーネントの状態が不正に引き継がれてしまう可能性があります。
どうしても一意のIDが取得できず、かつ要素の並べ替えや削除が絶対に起きないのであれば、暫定的にインデックスを使うこともあります。しかし、基本的にはユニークなIDを準備するのが理想です。
3. key はリスト内で一意ならOK
複雑に考えがちですが、React が必要としているのは**「同じリスト内で一意」**なキーです。
同じコンポーネントが複数あったとしても、それぞれのリストごとにキーがユニークであれば問題ありません。
たとえば、A コンポーネントにリストがあって、B コンポーネントにもリストがあって、それぞれのリストが別のデータを扱うとき、両リストでキーの値が重複していても、それぞれのコンポーネントが独立している限りは衝突しません。
キーを指定しないとどうなる?
先ほどのサンプルのように、キーを指定しないまま書いた場合は、React から警告が表示されます。警告を無視してもコードは動作することが多いですが、以下のようなデメリットがあります。
パフォーマンス低下: どの要素が変更されたのかを判定しづらくなり、無駄な再レンダーが起きる可能性がある
予測不能な振る舞い: フォーム要素や入力値を含むコンポーネントが並び替えられた場合に、入力値やコンポーネントの状態が違う要素に引き継がれるリスクがある
React は高速なUI更新を実現するためにキーを頼りにしているので、正しくキーを指定することはReact の基本ルールと言えます。
まとめ
リスト要素にキーを指定することはReactにおける必須事項であり、適切なキーがない場合はパフォーマンス上も機能上も問題が発生しやすいです。
API やDBからユニークなIDを使う
インデックスを使うのはなるべく避ける
リスト内で重複しないキーを付与する
これらのポイントを押さえておけば、React アプリケーションを安定的かつ効率的に動作させることができます。ぜひ、日々の開発で意識してみてください。
もしデータにユニークなIDが存在しない場合は、以下のような方法を検討しても良いでしょう。
新規要素を作るタイミングで UUID や連番を付ける
DBやサーバーが生成してくれるユニークキーがあればそれを利用する
(どうしても動的な並び替えが行われない確証がある場合にのみ)インデックスを利用する
React のドキュメントにもキーに関する解説があるので、公式ドキュメントも合わせて確認してみてください。