React
key 属性的作用与最佳实践
key 是 React 在处理列表时用来标识元素身份的属性。它帮助 React 的 diff 算法精准追踪和复用 DOM 节点。
一、key 的三个核心作用
1. 元素的唯一标识
在列表中,key 帮助 React 区分每个元素的身份。相同的 key 被认为是同一个逻辑元素。
2. 性能优化
通过 key,React 能正确匹配新旧元素,最小化 DOM 操作——只更新真正变化的节点。
3. 组件状态维护
当列表顺序改变时,key 确保组件状态(如表单输入、滚动位置)与正确的数据项关联。
二、工作原理
在虚拟 DOM 的 diff 过程中:
// 一个包含输入框的列表项
function TodoItem({ id, text }: { id: string; text: string }) {
const [input, setInput] = React.useState('')
return (
<div>
<span>{text}</span>
<input value={input} onChange={(e) => setInput(e.target.value)} />
</div>
)
}
// 错误:使用 index 作为 key
function BadList({ todos }: { todos: Array<{ id: string; text: string }> }) {
return (
<ul>
{todos.map((todo, index) => (
<li key={index}>
<TodoItem id={todo.id} text={todo.text} />
</li>
))}
</ul>
)
}
// 正确:使用稳定的唯一 id
function GoodList({ todos }: { todos: Array<{ id: string; text: string }> }) {
return (
<ul>
{todos.map((todo) => (
<li key={todo.id}>
<TodoItem id={todo.id} text={todo.text} />
</li>
))}
</ul>
)
}当 key 相同时,React 认为是同一个元素,复用 DOM 节点,只更新 props 和内容。
当 key 不同时,React 销毁旧元素,创建新元素——内部状态会丢失。
三、最佳实践与常见错误
✓ 使用稳定的唯一标识
优先用后端返回的 ID,或数据本身的唯一字段(邮箱、用户名等)。
✗ 避免使用数组 index
当列表可能被过滤、排序或插入新项时,index 会改变,导致:
- 组件状态错乱(输入框内容跑到其他行)
- 不必要的重渲染和性能下降
- 难以追踪的 bug
✓ 保持 key 的唯一性
同一级列表中的 key 必须唯一。父列表和子列表的 key 不需要全局唯一,但同级必须不重复。
特殊场景:动态组件强制重置
function Form({ userId }: { userId: string }) {
const [data, setData] = React.useState({ name: '', age: '' })
// 通过改变 key 强制销毁并重建组件,清空状态
return (
<>
<FormFields key={userId} data={data} onChange={setData} />
</>
)
}当 userId 改变时,key 随之改变,React 会销毁旧组件并创建新组件,自动重置表单状态。
一句话记住:key 是 React 识别"这个元素是谁"的关键。用稳定的唯一 ID,避免 index,确保组件状态和性能都不出错。