React 警告Each child in a list should have a unique “key” prop一句话总结用「唯一 ID 稳定不变 不用索引」三件套让列表渲染既稳定又高效黄字警告瞬间消失正文目录警告含义React 在挑剔什么「key」5 大高频翻车场景 修复代码万能兜底key 的选择策略预防 checklist不再踩坑一句话总结一、警告含义React 在挑剔什么「key」当你在控制台看到Warning: Each child in a list should have a unique key prop.React 在告诉你「你在用 map 渲染列表时每个子元素缺少一个独一无二的 key 属性。没有 keyReact 无法高效地追踪哪些元素变了、哪些新增了、哪些删除了。」没有 key 的后果React 强制全量重新渲染列表性能严重下降列表项有状态如输入框内容时状态会错位动画效果异常DOM 复用出错本质React 需要 key 来做高效的 Diff 比对。二、5 大高频翻车场景 修复代码① 完全没有写 key// ❌ 没有 key function TodoList({ todos }) { return ( ul {todos.map(todo ( li{todo.text}/li // ❌ 缺少 key ))} /ul ); }修复加上 key使用数据的唯一 ID// ✅ 使用唯一 ID 作为 key function TodoList({ todos }) { return ( ul {todos.map(todo ( li key{todo.id}{todo.text}/li // ✅ 唯一 key ))} /ul ); }② 使用数组索引index作为 key// ❌ 用 index 作为 key function TodoList({ todos }) { return ( ul {todos.map((todo, index) ( li key{index} // ❌ index 作为 key input defaultValue{todo.text} / /li ))} /ul ); }当你在列表头部插入/删除/排序时index key 会导致严重问题每个列表项的 key 都变了React 会错误地复用 DOM 节点输入框内容会错位。修复使用数据的唯一 ID// ✅ 使用数据唯一 ID function TodoList({ todos }) { return ( ul {todos.map(todo ( li key{todo.id} // ✅ 稳定的唯一 ID input defaultValue{todo.text} / /li ))} /ul ); }③ 使用随机值作为 key// ❌ 用 Math.random() 作为 key function ProductList({ products }) { return ( div {products.map(product ( div key{Math.random()} // ❌ 每次渲染都变 → 全部重新挂载 {product.name} /div ))} /div ); }使用随机值和没写 key 一样糟糕。每次渲染时 key 都不同React 会认为所有的旧元素都被删除了新的都是新增的导致所有组件都被卸载再重新挂载丢失所有内部状态动画效果全部重置修复使用稳定唯一 ID// ✅ 使用稳定的唯一 ID function ProductList({ products }) { return ( div {products.map(product ( div key{product.id} // ✅ 稳定唯一 {product.name} /div ))} /div ); }④ key 不唯一多个元素共享同一个 key// ❌ 多个元素用了相同的 key function CategoryList({ items }) { return ( div {items.map(item ( div key{item.category} // ❌ 同一分类多个 itemkey 重复 {item.name} /div ))} /div ); }当两个元素共享同一个 key 时React 会困惑它不知道该保留哪个、该删除哪个。这会导致渲染错乱。修复确保每个元素都有独一无二的 key// ✅ 使用 item 级别的唯一 ID function CategoryList({ items }) { return ( div {items.map(item ( div key{item.id} // ✅ 每个 item 有唯一 ID [{item.category}] {item.name} /div ))} /div ); }⑤ 使用对象引用作为 key每次都变// ❌ 用对象引用作为 key → 每次渲染都是新引用 function List({ data }) { const items data.map(d ({ ...d, label: d.name.toUpperCase() })); return ( div {items.map(item ( div key{item} // ❌ 对象引用每次都不同 {item.label} /div ))} /div ); }每次渲染items都是全新的对象数组用item对象作为 key 等同于没用 key。修复使用基本类型的唯一标识// ✅ 使用基本类型 ID function List({ data }) { const items data.map(d ({ ...d, label: d.name.toUpperCase() })); return ( div {items.map(item ( div key{item.id} // ✅ 基本类型 ID稳定不变 {item.label} /div ))} /div ); }三、万能兜底key 的选择策略场景推荐 key不推荐有后端唯一 IDitem.idindex、random无后端 ID有唯一字段item.email/item.slugindex组合唯一值${item.category}-${item.id}单一非唯一字段无任何唯一字段迫不得已crypto.randomUUID()在数据创建时生成index、Math.random()纯静态列表永远不增删改勉强可用 indexrandom、对象引用万能模板function SafeList({ items }) { return ( ul {items.map(item ( // ✅ 三原则唯一 稳定 基本类型 li key{item.id ?? crypto.randomUUID()} {item.content} /li ))} /ul ); }重要crypto.randomUUID()只在数据首次创建时调用一次千万不要放在 map 里每次都生成四、预防 checklist所有.map()渲染的列表元素必须有 keykey 必须是唯一的列表内不重复key 必须是稳定的数据不变化 key 就不变key 必须是基本类型string 或 number不是对象绝对不用index 作为动态列表的 key绝对不用Math.random() / Date.now() 作为 key控制台「Each child in a list should have a unique “key”」 立即给 map 内的顶层元素加上 key五、一句话总结「Each child in a list should have a unique “key” prop」 列表中缺少稳定唯一的标识。用「唯一 ID 稳定不变 基本类型」三件套让列表 Diff 精准高效警告永远消失最后问候亲爱的朋友们并邀请你们阅读我的全新著作 《 React开发实践掌握Redux与Hooks应用 》