FumadocsZDecode
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,确保组件状态和性能都不出错。

On this page