在React中,key
是一个特殊属性,用于帮助React识别列表中元素的变化,优化渲染性能,并保持组件状态。正确使用key
是React开发中的基础知识点。
为什么需要Key?
当React渲染列表时,如果没有key
,React无法有效识别哪些元素发生了变化。这会导致:
- 不必要的重新渲染
- 组件状态丢失
- 可能出现诡异的渲染问题
Key的核心原则
- 唯一性:同一列表中,key必须唯一
- 稳定性:key应该是稳定的,不应随组件状态变化而变化
- 关联性:key应与数据本身关联,而非位置
✅ 重要提示:key只需要在当前列表中唯一即可,不同列表之间可以重复。
常见错误:使用索引(index)作为key
错误示例(使用index作为key):
function TodoList() {
const [todos, setTodos] = useState([
{ id: 1, text: '学习key的使用' },
{ id: 2, text: '修复bug' }
]);
const deleteTodo = (index) => {
setTodos(todos.filter((_, i) => i !== index));
};
return (
<ul>
{todos.map((todo, index) => (
<li key={index}>
<input type="text" placeholder="编辑待办" />
{todo.text}
<button onClick={() => deleteTodo(index)}>删除</button>
</li>
))}
</ul>
);
}
问题分析:
当删除第一个待办项后,输入框的状态会错误地保留在第一个位置,因为React认为key为0的元素仍然存在,只是位置发生了变化。
正确使用方法:使用数据的唯一标识符
正确示例(使用唯一id作为key):
function TodoList() {
const [todos, setTodos] = useState([
{ id: 1, text: '学习key的使用' },
{ id: 2, text: '修复bug' }
]);
const deleteTodo = (id) => {
setTodos(todos.filter(todo => todo.id !== id));
};
return (
<ul>
{todos.map(todo => (
<li key={todo.id}>
<input type="text" placeholder="编辑待办" />
{todo.text}
<button onClick={() => deleteTodo(todo.id)}>删除</button>
</li>
))}
</ul>
);
}
为什么使用唯一ID更好?
受控组件示例:
// 假设数据源为 ['张三','李四','王五']
// 使用唯一ID作为key
// 渲染: 张三 李四 王五
// 当数据源重排为 ['王五','张三','李四']
// 使用唯一ID: 王五 张三 李四
// React知道只是顺序变化,不会重新渲染,只是移动元素
// 如果使用index作为key:
// 重排后: 王五 张三 李四
// React会认为三个元素都发生了变化,导致重新渲染
非受控组件(如input)示例:
// 使用index作为key
// 输入: 0 1 2
// 添加新元素在开头: 5 0 1 2
// 问题: 输入框内容没有正确关联到对应的元素
// 使用唯一ID作为key
// 输入: 0 1 2
// 添加新元素在开头: 5 0 1
// 正确: 输入框内容正确关联到对应的元素
不同列表可以使用相同key
<div>
<ul>
{users.map(user => (
<li key={user.id}>{user.name}</li>
))}
</ul>
<ul>
{products.map(product => (
<li key={product.id}>{product.name}</li>
))}
</ul>
</div>