react-key-prop
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseReact: Key Prop Best Practices
React:Key Prop最佳实践
Core Principle
核心原则
Use stable, unique IDs from your data. Never use array index for dynamic lists.
The prop provides stable identity to list elements during React's reconciliation process.
key使用数据中稳定、唯一的ID。绝对不要在动态列表中使用数组索引。
keyWhen to Use What
不同场景的使用方案
Use Data IDs (Preferred)
使用数据自带的ID(首选)
Always use unique, stable identifiers directly from your data:
jsx
// ✅ Correct
{todos.map((todo) => (
<li key={todo.id}>{todo.text}</li>
))}Ideal keys are:
- Unique - No two items share the same key
- Stable - Never changes during component lifetime
- Predictable - Directly tied to the data item
始终直接使用数据中唯一、稳定的标识符:
jsx
// ✅ 正确写法
{todos.map((todo) => (
<li key={todo.id}>{todo.text}</li>
))}理想的key需满足:
- 唯一性 - 没有两个项使用相同的key
- 稳定性 - 在组件生命周期内永远不会改变
- 可预测性 - 直接与数据项绑定
Generate IDs on Data Load
在数据加载时生成ID
When data lacks IDs, create them once when receiving data:
jsx
import { nanoid } from 'nanoid';
useEffect(() => {
fetch('/api/items')
.then(res => res.json())
.then(data => {
const itemsWithIds = data.map(item => ({
...item,
_tempId: nanoid() // Stable ID generated once
}));
setItems(itemsWithIds);
});
}, []);当数据没有自带ID时,在首次接收数据时生成一次:
jsx
import { nanoid } from 'nanoid';
useEffect(() => {
fetch('/api/items')
.then(res => res.json())
.then(data => {
const itemsWithIds = data.map(item => ({
...item,
_tempId: nanoid() // 生成一次的稳定ID
}));
setItems(itemsWithIds);
});
}, []);When Index Is Acceptable (Rare)
何时可以使用索引(极少情况)
Index as key is acceptable ONLY when ALL conditions are met:
- List is absolutely static
- Items never added/removed (except at the end)
- Order never changes
- Items have no internal state
只有当所有以下条件都满足时,才可以将索引作为key:
- 列表是完全静态的
- 项不会被添加/移除(除了在末尾)
- 顺序永远不会改变
- 项没有内部状态
Anti-Patterns to Avoid
需要避免的反模式
Never Generate Keys During Render
绝对不要在渲染时生成key
jsx
// ❌ WRONG: Creates new key every render
{items.map(item => (
<li key={Math.random()}>{item.name}</li>
))}This forces React to destroy and recreate all components on every render.
jsx
// ❌ 错误写法:每次渲染都会生成新的key
{items.map(item => (
<li key={Math.random()}>{item.name}</li>
))}这会迫使React在每次渲染时销毁并重新创建所有组件。
Don't Use Index for Dynamic Lists
不要在动态列表中使用索引
jsx
// ❌ WRONG for dynamic lists
{items.map((item, index) => (
<li key={index}>{item.name}</li>
))}Index fails when:
- Items are added/removed from beginning or middle
- List order changes (sorting, filtering)
- Items have internal state (like form inputs)
The bug: Index represents position, not data identity. When positions change but indexes stay the same, React incorrectly "mutates" existing components instead of creating new ones, causing state mismatch.
jsx
// ❌ 动态列表的错误写法
{items.map((item, index) => (
<li key={index}>{item.name}</li>
))}索引在以下场景中会失效:
- 在列表开头或中间添加/移除项
- 列表顺序改变(排序、筛选)
- 项拥有内部状态(比如表单输入)
问题所在:索引代表的是位置,而非数据标识。当位置改变但索引保持不变时,React会错误地“修改”现有组件而非创建新组件,导致状态不匹配。
Don't Use useId()
for List Keys
useId()不要使用useId()
作为列表key
useId()React's hook is for accessibility (linking labels to inputs), not for generating list keys.
useId()React的钩子是用于无障碍功能(将标签与输入框关联)的,而非生成列表key。
useId()Quick Reference
快速参考
DO
应该做
- Always use when rendering lists
key - Prefer unique, stable from your data
id - Generate IDs once at data load time (/
nanoid)uuid
- 渲染列表时始终使用
key - 优先使用数据中唯一、稳定的
id - 在数据加载时生成一次ID(使用/
nanoid)uuid
DON'T
不应该做
- Never generate during render (
key,Math.random())Date.now() - Avoid as
indexfor dynamic listskey - Don't use for list keys
useId()
- 绝对不要在渲染时生成(比如
key、Math.random())Date.now() - 避免在动态列表中使用作为
indexkey - 不要将用于列表key
useId()