文章中英模式
布鲁斯前端React面试题目 - 解释 React Key 的用途
深入解析React中key属性的作用、如何正确使用key、常见错误以及对性能的影响。了解为何不应使用索引作为key,key如何协助React识别元素变化,以及React协调算法与key的关系。
文章中英模式

懒得看文章?那就来看视频吧
React Key 的作用是什么?
在React中,key 是一个特殊的props,主要用于帮助React识别列表中的元素。它就像是每个元素的「身份证」,让React能快速找出哪些元素有变化。
Key的主要作用:
- 1. 提升DOM更新效率
- 2. 保持组件状态不丢失
- 3. 避免不必要的重新渲染
- 4. 确保列表元素的唯一性
Key 与 React 渲染列表的关系
当React渲染列表时,它需要知道哪些元素需要更新、新增或删除。
没有key:React只能按位置比较
原列表:
位置0: 苹果
位置1: 香蕉
位置2: 橘子
新增「芒果」到开头:
位置0: 苹果→芒果 (更新)
位置1: 香蕉→苹果 (更新)
位置2: 橘子→香蕉 (更新)
位置3: 新增橘子
有key:React可按身份比较
原列表:
key="a": 苹果
key="b": 香蕉
key="c": 橘子
新增「芒果」到开头:
key="m": 新增芒果
key="a": 苹果 (不变)
key="b": 香蕉 (不变)
key="c": 橘子 (不变)
使用索引作为key的问题
⚠️ 当列表顺序会有所改变时,索引key会导致不必要的DOM更新:
// 如果列表会更新,不好的做法
{items.map((item, index) => (
<Item key={index} data={item} />
))}
// 好的做法
{items.map(item => (
<Item key={item.id} data={item} />
))}Key 也可被用于强制重新创建组件
组件的实例、状态和DOM与其key密切相关。当key改变时,即使组件类型相同,React也会:
- 1. 完全卸载旧组件实例(触发
useEffect的清理函数) - 2. 创建新组件实例(重新触发
useEffect) - 3. 重置组件的所有内部状态
- 4. 重建DOM节点
这种行为可以被有意利用来强制重置组件状态:
// 使用key重置表单组件
function ResetableForm({ formData, resetKey }) {
return (
<Form
key={resetKey} // 当resetKey改变时,整个Form组件会重置
initialValues={formData}
>
{/* 表单内容 */}
</Form>
);
}
// 使用案例
function ProfileEditor() {
const [user, setUser] = useState(null);
const [resetCounter, setResetCounter] = useState(0);
// 当用户切换时,我们可以通过改变key来重置表单
return (
<div>
<UserSelector onSelect={setUser} />
<ResetableForm
formData={user}
resetKey={user?.id || resetCounter}
/>
<button onClick={() => setResetCounter(c => c + 1)}>
重置表单
</button>
</div>
);
}Key 的最佳实践
选择正确的key
- 优先使用稳定、唯一的ID: 数据通常有固有的ID,如数据库主键、UUID等
- 其次考虑内容哈希: 如果没有ID,可基于内容生成哈希值
- 避免使用随机值: 每次渲染产生的随机key会导致所有组件重新渲染
- 最后才考虑索引: 只在项目稳定不变、没有重新排序时使用索引
常见错误
// ❌ 错误:使用索引作为可变列表的key
{items.map((item, index) => (
<TodoItem key={index} item={item} />
))}
// ❌ 错误:使用随机值或时间戳作为key
{items.map(item => (
<TodoItem key={Math.random()} item={item} />
))}
// ✅ 正确:使用固有ID
{items.map(item => (
<TodoItem key={item.id} item={item} />
))}
// ✅ 替代方案:结合索引和稳定识别属性
{items.map((item, index) => (
<TodoItem key={`${item.name}-${index}`} item={item} />
))}🔥 常见面试题目
(一) React中为什么需要key?不提供key会有什么后果?
解答: React用key来识别列表中的元素,就像每个人的身份证号码。有了key,React才能:
- 1. 知道哪些元素变了、新增了或删除了
- 2. 决定能否重用元素而不是重建
- 3. 正确保留元素状态
没有key的后果:
原始列表
删除A后
没提供key时,React默认用索引,这在列表变动时会导致:
- 1. 性能下降(过度重建DOM)
- 2. UI混乱(如错误的选中状态)
- 3. 状态错乱(如输入框内容跑错位置)
(二) 为什么不建议使用索引作为key?什么情况下可以使用?
解答: 索引只是位置编号,不代表项目本身。当列表变动时,同一索引可能对应不同项目:
// 原列表:索引与项目的对应
[0: 苹果, 1: 香蕉, 2: 橘子]
// 删除苹果后:同样的索引现在对应不同项目!
[0: 香蕉, 1: 橘子]这会导致:
- 1. 组件被不必要地重建
- 2. 表单输入值跑位
- 3. 状态混乱
只有在这些条件全部满足时才能用索引:
- 1. 列表永远不会重排序
- 2. 不会添加/删除项目
- 3. 项目没有ID
- 4. 组件没有状态
(三) 如何正确生成key值?有哪些常见策略?
解答: 好的key应该是稳定且唯一的,按优先级:
- 数据ID:最理想的选择
<Item key={user.id} /> - 内容哈希:当没有ID时
<Item key={hash(item.content)} /> - 生成ID:初始化时创建
// 初始化时添加ID const data = items.map(i => ({...i, id: uuid()}))