ReactでTodoリストを map でレンダーする際、各 li 要素の key に指定する値として最も適切なものはどれですか?
1〜4キーで選択、Enterで回答できます
解説
正解は「Todo 作成時に crypto.randomUUID() で生成し」です。key には、兄弟要素の中で一意であり、かつレンダーをまたいで変わらない値を使います。データを作る時点で一度だけ id を生成して保存しておけば、両方の条件を満たせます。id を生成するタイミングが重要import { useState } from "react"; export default function TodoApp() { const [todos, setTodos] = useState([]); const [text, setText] = useState(""); function handleAdd() { // 追加時に一度だけ id を生成し、データとして保存する setTodos([...todos, { id: crypto.randomUUID(), title: text }]); setText(""); } return ( <> <input value={text} onChange={(e) => setText(e.target.value)} /> <button onClick={handleAdd}>追加</button> <ul> {todos.map((todo) => ( <li key={todo.id}>{todo.title}</li> // 保存済みの id を使う ))} </ul> </> ); }crypto.randomUUID() はブラウザ標準の、ほぼ重複しないランダムな ID を作る関数です(HTTPS または localhost で利用できます)。他の値が不適切な理由「レンダーのたびに crypto.randomUUID() で」生成すると、一意ではあっても毎回 key が変わります。React は別の要素とみなして作り直すため、state が失われ、パフォーマンスも悪化します。「Todo のタイトル文字列」は、同じタイトルの Todo を追加した時点で key が重複します。タイトルを編集すると key も変わってしまいます。インデックスの key は削除や先頭追加で入力内容が別の行に残る「map のコールバックで受け取る配列のインデックス」は、追加・削除・並べ替えが一切ないリストなら問題なく動くため、つい使いがちです。しかし Todo を削除すると後ろの行のインデックスが1つずつ繰り上がり、React は「同じ key の要素が残った」と判断します。その結果、各行が持つチェック状態や編集中の入力値が、隣の Todo に引き継がれたように見える不具合が起きます。Todo のように要素が増減するリストでは、インデックスを key にするのは避けましょう。参考リストのレンダー – React