← 返回题目列表

React 中 key 除了列表 Diff 还有什么作用?

中等 第 19 / 27 题 更新于 2026/07/29
Reactkey状态重置组件复用

简化版

key 不只用于列表 Diff,还决定同一位置的组件身份。key 变化时 React 会认为这是新组件,卸载旧实例并挂载新实例,因此可以用来重置表单、切换详情页状态或避免状态串用。

详细版

React 根据元素类型和 key 判断组件是否复用。

<UserForm key={userId} userId={userId} />

userId 从 1 变成 2,key 也变化,React 会重新创建 UserForm,内部 state 回到初始值。如果不加 key,同一位置同一类型组件会被复用,内部 state 可能保留。

面试中要讲清:key 是组件身份标识,不是只给 map 用;但也不能滥用随机 key,否则每次渲染都会重挂载,性能和状态都会出问题。

完整版教学

一、key 的本质是身份标识

React 渲染时会比较新旧元素。 如果同一位置元素类型相同、key 也相同,React 倾向复用旧组件实例。 如果 key 不同,就认为身份变了,需要卸载旧组件再挂载新组件。

type 相同 + key 相同 -> 复用实例
type 相同 + key 不同 -> 重建实例
type 不同 -> 重建实例

这解释了为什么 key 不只影响列表。 任何组件只要处在可比较的位置,key 都可能影响它是否被复用。

二、列表 Diff 只是最常见场景

在列表里,key 帮 React 识别每个元素对应哪条数据。 插入、删除、排序时,稳定 key 能让 React 少移动 DOM,避免状态错位。 这也是面试高频点。

items.map(item => (
  <TodoItem key={item.id} item={item} />
))
key 选择插入排序表现风险
稳定 id身份准确推荐
index顺序变化时错位表单状态可能串
random每次都变全量重建

假设列表有 10 项,在开头插入 1 项。 用 id 时 React 知道旧 10 项只是位置后移;用 index 时,很多组件身份会被错误复用。

三、key 变化可以主动重置组件状态

有些时候复用不是你想要的。 例如用户详情页从 userId=1 切到 userId=2,表单内部草稿不应该沿用上一个用户。 这时可以给组件加上和业务身份相关的 key。

function UserPage({ userId }: { userId: string }) {
  return <UserEditor key={userId} userId={userId} />
}
userId=1 -> UserEditor 实例 A
userId=2 -> key 变化 -> 卸载 A,挂载实例 B

这个技巧非常实用。 它比在 effect 里手动清空十几个 state 更可靠,因为重挂载会自然回到初始状态。

四、不加 key 时同位置同类型会复用

React 默认按树位置匹配组件。 如果两个分支都渲染同一个组件类型,React 可能复用实例,从而保留内部 state。 这有时会产生意外。

{mode === 'create'
  ? <Form mode="create" />
  : <Form mode="edit" />}

上面两个分支都是 Form,位置也一样。 切换模式时内部输入状态可能不变。 如果希望重置,可以写:

<Form key={mode} mode={mode} />

这不是列表场景,却完全体现 key 的身份作用。

五、随机 key 是性能和状态杀手

有些人为了消除 key 警告,会写 key={Math.random()}。 这会让每次渲染 key 都不同,React 只能每次卸载并重建。 组件内部状态、DOM 焦点和缓存都会丢。

items.map(item => (
  <TodoItem key={Math.random()} item={item} />
))

如果页面每秒刷新 5 次,10 个列表项每秒就可能重挂载 50 次。 这不仅浪费性能,还会让输入框光标、动画和订阅状态异常。

六、key 的作用域只在兄弟节点之间比较

key 不需要全局唯一,只需要在同一组兄弟节点中唯一。 不同列表里使用同样的 id 没问题。 这个点能避免把 key 设计得过于复杂。

记忆钩子:key 不是编号牌,是身份证;身份证变了,React 就当新人。

回答时先讲列表,再拔高到“组件身份”。 这样能覆盖常规考点,也能回答状态重置类追问。

七、常见误区与追问

  • 误区:key 只在数组 map 中有用。 key 决定组件身份,非列表场景也能用来控制复用和重挂载。
  • 误区:index 作为 key 永远没问题。 列表会插入、删除、排序时,index 容易导致状态错位。
  • 误区:随机 key 可以快速解决警告。 随机 key 每次变化,会导致组件反复卸载和重建。
  • 追问:如何用 key 重置表单? 给表单组件设置业务身份 key,例如 key={userId}key={mode}
  • 追问:key 需要全局唯一吗? 不需要,只需要在同一层兄弟节点之间唯一。
  • 追问:key 变化会触发生命周期吗? 会卸载旧组件并挂载新组件,effect 清理和重新执行都会发生。

八、加强记忆

key 这题别只停在列表 Diff。它本质是 React 判断组件身份的线索:稳定 key 帮助复用,变化 key 触发重挂载,随机 key 制造灾难。列表用业务 id,状态重置用业务身份,简单静态列表才可谨慎用 index。