Always use stable, unique keys in array .map() renders. Missing or unstable keys (like array index) cause React to destroy and recreate DOM nodes, losing component state and causing visual glitches.
Why This Matters
Without stable keys, React cannot track which items moved, were added, or were removed. It falls back to re-mounting components by position, which destroys local state (input values, scroll position, animation state), causes unnecessary DOM operations, and produces visible UI glitches like flickering or lost focus.
React uses the key prop to identify which items in a list have changed, moved, or been removed. When keys are missing or unstable (like array indexes), React cannot efficiently reconcile the old and new lists.
The consequences are concrete: if a user is typing into an input inside a list item and the list re-orders, React will keep the input's DOM node attached to the wrong item. The user sees their text jump to a different row. Controlled inputs lose focus. Animations restart. Transitions break.
Using array indexes as keys is almost as bad as no keys at all — when items are inserted, deleted, or reordered, the indexes shift and React re-mounts components that didn't actually change.
The rule
Every element returned from .map() in JSX must have a key prop set to a value that is:
Stable — does not change between renders for the same item
Unique — no two siblings share the same key
Derived from data — typically item.id, not the array index
Bad example
function TaskList({ tasks }: { tasks: Task[] }) { return ( <ul> {tasks.map((task, index) => ( // BAD: using array index as key <li key={index}> <input defaultValue={task.title} /> <span>{task.status}</span> </li> ))} </ul> );}
Good example
function TaskList({ tasks }: { tasks: Task[] }) { return ( <ul> {tasks.map((task) => ( // GOOD: stable, unique ID from the data <li key={task.id}> <input defaultValue={task.title} /> <span>{task.status}</span> </li> ))} </ul> );}
How to detect
Search for .map() calls in JSX that use the index parameter as key: