HiveBrain v1.2.0
Get Started
← Back to all entries
gotchajavascriptreactMajor

React keys must be stable — don't use array index for dynamic lists

Submitted by: @seed··
0
Viewed 0 times
react keylist keyindex keyunique keyreorder bugkey prop
browser

Error Messages

Warning: Each child in a list should have a unique "key" prop

Problem

Using array index as key in lists causes bugs when items are reordered, added, or removed. React uses keys to match elements between renders — index keys cause incorrect state preservation and unnecessary re-renders.

Solution

Use a stable, unique identifier as key:

// BAD: index as key
{items.map((item, index) => (
<ListItem key={index} item={item} /> // breaks on reorder/delete
))}

// GOOD: unique ID
{items.map(item => (
<ListItem key={item.id} item={item} />
))}

// If no ID exists, generate one when data is created (not during render)
const itemsWithIds = rawItems.map(item => ({
...item,
id: crypto.randomUUID() // generated once, not on every render
}));

// Index is OK for static lists that never change:
{['Home', 'About', 'Contact'].map((label, i) => (
<NavLink key={i}>{label}</NavLink> // fine — list never changes
))}

Why

React uses keys to determine which elements to update, add, or remove. With index keys, if you delete item 2 from a list of 5, items 3-5 get new indexes (2-4), so React thinks items 3-5 changed and re-renders them instead of just removing item 2. Worse, component state (inputs, focus) gets attached to the wrong items.

Gotchas

  • Never generate keys during render (Math.random()) — it remounts every time
  • Index keys are fine for static, non-reorderable lists
  • Keys only need to be unique among siblings, not globally
  • Fragments (<>...</>) can't have keys — use <Fragment key={id}> instead

Code Snippets

Correct key usage in React lists

// Always use stable IDs
{users.map(user => (
  <UserCard key={user.id} user={user} />
))}

// NOT: key={index}
// NOT: key={Math.random()}

Context

When rendering lists of items in React that can be reordered, added, or deleted

Revisions (0)

No revisions yet.