Why keys matter (and how bad keys break apps)
Keys give list items a stable identity so React's reconciler can match elements across renders. Good keys = correct minimal updates. Bad keys (index, or random each render) cause wrong state/DOM reuse, lost focus and input values, broken animations, and unnecessary re-renders.
Keys are how React's reconciler tracks identity — "which item is which" — across renders. Get them wrong and React reuses the wrong DOM and state.
What keys actually do
When a list re-renders, React diffs the new array of elements against the old one. The key tells it which old element corresponds to which new one. With correct keys, React can tell that item C was removed from [A, B, C, D] and only touch the DOM for C — minimal, correct updates.
Without a stable identity, React falls back to matching by position.
How bad keys break things
1. Index as key + list mutation. If you key by array index and then insert/remove/reorder, the indices stay the same but now point to different data. React thinks "item at index 1 still exists, just with new props" and reuses that DOM node and its component state for a different item. Symptoms:
- Wrong input values — you delete the 2nd todo, the 3rd todo's text input now shows the 2nd's value.
- Lost or misplaced focus — focus jumps to the wrong row.
- Stale local state — a checkbox/expanded state sticks with the position, not the item.
- Broken animations — enter/exit transitions fire on the wrong elements.
2. Random key each render (key={Math.random()}). Now every item gets a brand-new key every render → React thinks every old element was removed and every new one added → it unmounts and remounts the entire list every render. You lose all component state, focus, scroll position, and pay a full re-render. Pure destruction.
3. Non-unique keys. Duplicate keys → React mis-associates elements and warns; behavior becomes unpredictable.
What makes a good key
- Stable — same item, same key, every render.
- Unique among siblings.
- Derived from the data's identity — a database id, a UUID generated when the item was created. Not the index, not random, not something that changes.
Index keys are acceptable only when the list is static — never reordered, inserted into, or filtered — and items have no local state.
The framing
"Keys give list items a stable identity so React's reconciler knows which element maps to which across renders, enabling correct minimal updates. Index keys break the moment the list mutates — indices point at new data, so React reuses DOM and state for the wrong item: wrong input values, misplaced focus, stale local state, broken animations. Random keys are worse — they remount the whole list every render. A good key is stable, unique, and tied to the data's identity, like a real id. Index is only safe for a static, stateless list."
Follow-up questions
- •Walk through exactly what breaks when you delete a middle item with index keys.
- •Why is key={Math.random()} catastrophic?
- •When is it actually OK to use the index as a key?
- •How does React use keys during reconciliation?
Common mistakes
- •Using the array index as the key for dynamic lists.
- •Using Math.random() or a fresh value as the key each render.
- •Non-unique keys among siblings.
- •Thinking keys are just to silence the console warning.
- •Putting the key on the wrong element (must be on the outermost element of the map).
Performance considerations
- •Good keys let React do minimal DOM updates; index keys cause unnecessary re-renders of items that didn't change; random keys force a full unmount/remount of the list every render — the worst case.
Edge cases
- •Reordering, inserting, or filtering an index-keyed list.
- •List items with local state (inputs, checkboxes, expanded panels).
- •Items with enter/exit animations.
- •Two lists rendered together with overlapping keys.
Real-world examples
- •A todo list where deleting an item makes the wrong input value appear.
- •A reorderable list losing checkbox state because of index keys.