面试题:React 中 key 的作用是什么?

在 React 中,key 是一个特殊的字符串属性,用于帮助 React 识别哪些元素发生了变化、被添加或被删除,从而在渲染列表时高效地更新 DOM。

核心作用:标识列表中元素的唯一性

当 React 渲染一个列表(如 map 生成的 JSX 元素数组)时,它需要一种机制来追踪每个元素的身份。key 就是这个身份标识。

// ✅ 推荐:使用唯一 ID 作为 key
const todoList = todos.map((todo) => (
  <li key={todo.id}>{todo.text}</li>
));

如果没有 key,React 只能根据元素的索引位置来判断变化,这会导致性能问题和状态错乱。


为什么需要 key?(对比有无 key 的区别)

情景:在列表开头插入一个新项

假设有一个列表:['Alice', 'Bob']

现在在开头插入 'Charlie',变为:['Charlie', 'Alice', 'Bob']

  • 没有 key(或使用索引作为 key)
    • React 认为:
      • 索引 0:从 'Alice' 变为 'Charlie'更新元素
      • 索引 1:从 'Bob' 变为 'Alice'更新元素
      • 索引 2:新增 'Bob'创建元素
    • 结果:React 会重新渲染所有三个元素,效率低下。
  • 有稳定 key(如 user.id
    • React 认为:
      • 'Charlie'新元素 → 创建
      • 'Alice' (key=’alice’) 和 'Bob' (key=’bob’) 未变 → 复用
    • 结果:React 只创建新元素,复用原有元素,性能更优。

key 的选择原则

✅ 推荐:使用稳定、唯一、不变的 ID

// 最佳实践:使用数据本身的唯一 ID
const users = usersList.map((user) => (
  <UserCard key={user.id} user={user} />
));

⚠️ 不推荐:使用数组索引(index

// ❌ 仅在以下情况可接受:
// - 列表是静态的(不排序、不筛选、不增删)
// - 列表项没有内部状态或依赖顺序
const items = list.map((item, index) => (
  <div key={index}>{item.name}</div>
));

使用索引作为 key 的问题

  • 当列表重新排序或在中间插入/删除项时,索引会变化,导致 React 错误地复用组件实例。
  • 如果列表项内部有状态(如输入框),状态会错乱(输入框的值会“跳”到其他项上)。

key 的工作原理

  1. Diff 算法优化:React 在 reconciliation(协调)过程中,会比较新旧元素的 key
  2. 复用或销毁:如果 key 相同,React 认为是同一个元素,尝试复用并更新;如果 key 不同,则创建新元素或销毁旧元素。
  3. 不影响 propskey 不会作为 props 传递给组件,它仅在 React 内部使用。
function ListItem({ children }) {
  // key 不在 props 中
  console.log(props.key); // undefined
  return <li>{children}</li>;
}

key 应该放在哪里?

key 应该赋值给数组中直接返回的 JSX 元素,而不是该元素内部的子元素。

// ✅ 正确:key 在 <li> 上
const listItems = todos.map((todo) =>
  <li key={todo.id}>
    {todo.text}
  </li>
);

// ❌ 错误:key 在 <div> 内部,无效
const listItems = todos.map((todo) =>
  <li>
    <div key={todo.id}>{todo.text}</div>
  </li>
);

总结

要点说明
作用帮助 React 识别列表元素的身份,优化渲染性能。
推荐值使用数据中稳定、唯一、不变的 ID(如数据库 ID)。
避免使用数组索引(除非列表完全静态)。
位置放在 map 返回的最外层 JSX 元素上。
特殊性仅 React 内部使用,不会传递给组件 props

核心思想key 是 React 高效更新列表的“身份证”。使用正确的 key 可以避免不必要的重新渲染,防止状态错乱,是编写高性能 React 应用的关键实践。

THE END
喜欢就支持一下吧
点赞10 分享