react-key-prop

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

React: Key Prop Best Practices

React:Key Prop最佳实践

Core Principle

核心原则

Use stable, unique IDs from your data. Never use array index for dynamic lists.
The
key
prop provides stable identity to list elements during React's reconciliation process.
使用数据中稳定、唯一的ID。绝对不要在动态列表中使用数组索引。
key
prop在React的协调过程中为列表元素提供稳定的标识。

When 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()
作为列表key

React's
useId()
hook is for accessibility (linking labels to inputs), not for generating list keys.
React的
useId()
钩子是用于无障碍功能(将标签与输入框关联)的,而非生成列表key。

Quick Reference

快速参考

DO

应该做

  • Always use
    key
    when rendering lists
  • Prefer unique, stable
    id
    from your data
  • Generate IDs once at data load time (
    nanoid
    /
    uuid
    )
  • 渲染列表时始终使用
    key
  • 优先使用数据中唯一、稳定的
    id
  • 在数据加载时生成一次ID(使用
    nanoid
    /
    uuid

DON'T

不应该做

  • Never generate
    key
    during render (
    Math.random()
    ,
    Date.now()
    )
  • Avoid
    index
    as
    key
    for dynamic lists
  • Don't use
    useId()
    for list keys
  • 绝对不要在渲染时生成
    key
    (比如
    Math.random()
    Date.now()
  • 避免在动态列表中使用
    index
    作为
    key
  • 不要将
    useId()
    用于列表key

References

参考资料