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.
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
| Key | When to use |
|---|---|
A stable id from your data | The default. Always prefer this |
| A truly unique string | e.g., a slug, an email, a UUID |
| The array index | Only 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
0was “A”, is now “X” → update - key
1was “B”, is now “A” → update - key
2was “C”, is now “B” → update - key
3is 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 →