Keys

How React Identifies Items Across Renders

Keys

Keys are how React matches up old and new list items so it can reuse DOM nodes instead of recreating them.

4 min read Level 2/5 #react#keys#lists
What you'll learn
  • Pick stable, unique keys for list items
  • Avoid using array index as key for reorderable lists
  • Understand what keys do under the hood

A key prop tells React: “this item is the same one as last time”. React uses keys to match up old and new lists so it can move, keep, or remove existing DOM nodes — instead of throwing them away and making new ones.

The Rule

Every direct child rendered inside a list needs a unique, stable key among its siblings.

{users.map(user => <UserRow key={user.id} user={user} />)}

What Makes a Good Key

KeyWhen to use
A stable id from your dataThe default. Always prefer this
A truly unique stringe.g., a slug, an email, a UUID
The array indexOnly when the list never reorders/inserts/removes
Math.random()NEVER — different every render, defeats the purpose

Why Index Keys Bite You

Imagine a list [A, B, C] with index keys [0, 1, 2]. You prepend X, making the list [X, A, B, C] with indexes [0, 1, 2, 3].

React sees:

  • key 0 was “A”, is now “X” → update
  • key 1 was “B”, is now “A” → update
  • key 2 was “C”, is now “B” → update
  • key 3 is new → mount “C”

It updates every item, even though the right move was “insert X at the front”. And if any item had internal state (like a focused input or an open dropdown), that state goes to the wrong row.

With proper id keys:

{items.map(item => <Row key={item.id} item={item} />)}

React sees X is new, prepends it, and leaves A/B/C alone — DOM nodes intact, state preserved.

Keys Go On the Outermost Element

The key goes on the JSX returned from .map() — not inside the child component:

// ✓ Key on the mapped element
{users.map(u => <UserRow key={u.id} user={u} />)}

// ✗ Key inside the child does nothing useful
function UserRow({ user }) {
  return <li key={user.id}>{user.name}</li>;
}

When mapping to a Fragment that needs a key, use the long form:

{rows.map(r => (
  <Fragment key={r.id}>
    <dt>{r.term}</dt>
    <dd>{r.def}</dd>
  </Fragment>
))}

Keys Are Scoped to Siblings

Keys only need to be unique among the immediate siblings. Two separate lists can both have a key of "1". You don’t need globally unique ids.

Changing a Key Resets State

A side effect: when you change a component’s key, React unmounts and remounts it. That resets its state. Useful trick when you want a clean slate:

// Reset the form when user changes
<UserForm key={userId} userId={userId} />

You’ll see this used deliberately in the Patterns chapter.

Up Next

If you’re using TypeScript, here’s how to type your props. (If you’re not, this lesson is optional reading.)

Props with TypeScript →