React keys — why they matter
Keys give React identity for siblings in a list. Without stable keys, React matches children by position — reordering or inserting mid-list causes wrong component reuse: state, DOM, refs, and focus follow the slot, not the data. Use a stable, unique id from the data; never the array index unless the list is append-only and uneditable.
Keys are how React tells siblings apart during reconciliation. They are not for performance — they're for correctness.
Without keys, React matches by position.
Say you render:
items.map(item => <Row item={item} />)React sees children at positions 0, 1, 2. On the next render, the new positions 0, 1, 2 are diffed against the old. If you prepend a new item, every old row gets shifted into the slot of a different item — but React doesn't know it's a different item; it reuses the same fiber, the same DOM, the same state.
The visible bug:
- A row had focus on its input. Insert above → focus is now on a different row, same position.
- A row had collapsed state. Reorder → the collapsed state stays on the slot, not the item.
- Animations restart on the wrong items.
- Inputs show the wrong values because uncontrolled inputs keep their DOM state.
The fix: stable, unique key.
items.map(item => <Row key={item.id} item={item} />)Now React diffs by id: it can detect "row with id 7 moved from position 2 to position 0" and rearrange the existing fiber/DOM. State, refs, and focus follow the data.
Why key={index} is usually wrong.
items.map((item, i) => <Row key={i} ... />)Index-as-key is equivalent to no key — it just suppresses the warning. The keys still describe positions. Only safe when:
- The list is append-only and never reordered.
- List items are stateless (no input, no internal state).
- No animations or transitions tied to identity.
If any of those is false, use a stable id.
Common cases where the bug bites.
- Reorderable to-do lists (drag-and-drop).
- Filter / sort / search — items appear/disappear in arbitrary positions.
- Virtualized lists — rows scroll into view; index-as-key makes them inherit the wrong state.
- Forms with dynamic field arrays — first-row bug: removing the first row makes inputs show the second row's value.
Generating keys when no id exists.
- Best: persistent server id (
item.uuid, primary key). - Acceptable: deterministic hash of contents (when contents are unique).
- Last resort: generate a UUID at creation time and store it on the item.
- Never:
key={Math.random()}— fresh key every render, full unmount + remount of every row.
key to intentionally reset state.
The other side of keys: changing a key on the same component forces a remount. Useful when you want to reset a subtree's state cleanly:
<EditForm key={selectedItem.id} item={selectedItem} />When selectedItem changes, the form resets — no useEffect(() => setState(...), [item]) boilerplate.
Keys must be unique among siblings, not globally. Two siblings with the same key is a bug; the same key in a different parent is fine.
Senior takeaway. Keys aren't a perf optimization. They're React's identity contract for siblings. The performance benefit (less DOM work on reorder) is downstream of correctness. The interview answer is: keys identify children across renders so React can preserve state and reuse DOM correctly when the list changes.
Follow-up questions
- •Why is `key={index}` sometimes a bug but sometimes fine?
- •How can changing a key be used as a feature?
- •Why isn't `key={Math.random()}` a valid key strategy?
- •How does reconciliation use keys during a list reorder?
Common mistakes
- •Using array index as key on a reorderable / filterable list.
- •Using `Math.random()` as key — forces remount every render.
- •Putting keys on the wrapping `<div>` inside `Row` instead of on `<Row>` itself.
- •Duplicate keys among siblings — React warns and falls back to position.
Performance considerations
- •Stable keys let React move DOM nodes (cheap) instead of unmounting + remounting (expensive).
- •Fresh keys (Math.random) force a full subtree rebuild every render.
Edge cases
- •Adding items at the start of a list is the most common reveal-of-key-bug.
- •Virtualized lists — must use item id, not visible index.
- •Lists with duplicate content but distinct identity (two rows with same name, different id) — use the id.
Real-world examples
- •Any drag-and-drop reorder list. Form arrays in react-hook-form. Comment threads.