Reactのリスト表示でkeyに安定したIDを使う
Reactで配列を表示するとき、各要素にkeyを付けます。これは表示する項目を再描画の前後で対応付けるための目印です。
IDをkeyにする
type Item = { id: string; name: string };
const ItemList = ({ items }: { items: Item[] }) => (
<ul>
{items.map((item) => (
<li key={item.id}>{item.name}</li>
))}
</ul>
);keyは同じ一覧の兄弟要素の間で一意であればよく、データ全体で一意である必要はありません。
indexが問題になる場面
並べ替えや途中への追加・削除がある一覧で配列の位置をkeyにすると、位置が変わった別の項目を同じ要素と見なすことがあります。入力欄の値やコンポーネントの状態が、意図しない行へ残る原因になります。
// 並びが変わる一覧では避ける
{items.map((item, index) => <li key={index}>{item.name}</li>)}順序も件数も変わらない固定の一覧ならindexで問題にならない場合もあります。通常はデータが持つ安定したIDを選びます。描画中にcrypto.randomUUID()で毎回新しいkeyを作るのも避けてください。
入力欄で違いを確認する
各行に入力欄があるリストで先頭の行を削除し、残った入力欄の値を確認してみてください。indexをkeyにすると、Reactは「以前の0番目」と「現在の0番目」を同じ行として扱い、入力状態を別の項目へ引き継ぐことがあります。IDをkeyにすれば、項目の移動後も同じIDの行として対応付けられます。
keyは子コンポーネントの通常のpropsとしては渡されません。子でIDを使うなら、<ItemRow key={item.id} id={item.id} />のように別のpropsでも渡します。