What is the purpose of the 'key' prop, and what are common anti-patterns when assigning keys?
The `key` prop uniquely identifies elements in a list to guide React’s reconciliation algorithm during re-renders—ensuring efficient DOM updates and preserving component state correctly.
Short Answer
The key prop tells React which list items have changed, been added, or been removed—enabling stable identity across renders so the reconciler can minimize DOM mutations and retain local state (e.g., input focus, animation state) in the right components.
Details
React uses an O(n) heuristic list-diffing algorithm (not full tree diffing) that relies on keys to match old and new elements. When keys are present and stable, React preserves component instances and their internal state (e.g., useState, useRef, uncontrolled input values). Without keys—or with unstable keys—React falls back to index-based matching, causing unnecessary unmounts/remounts and lost state. Keys must be stable, predictable, and unique among siblings—but do not need to be globally unique. They are consumed by React and never passed to the component as a prop.
Common anti-patterns include:
- Using
Math.random()or timestamps → breaks stability → triggers full remounts. - Using array indices (
index) as keys when the list order changes (e.g., sorting, filtering, inserting) → misaligns state and DOM nodes. - Deriving keys from non-unique or mutable data (e.g.,
item.nameif names can duplicate or change). - Placing keys on the wrong element (e.g., on a wrapper
<div>instead of the direct mapped child)—keys must be on the immediate child returned bymap().
Example
// ❌ Anti-pattern: index key with dynamic list
{todos.map((todo, index) => (
<TodoItem key={index} todo={todo} /> // Breaks on reordering
))}
// ✅ Correct: stable, intrinsic ID
{todos.map(todo => (
<TodoItem key={todo.id} todo={todo} /> // Preserves identity & state
))}Bonus
To stand out: mention that keys affect component identity, not just DOM reuse—so even pure functional components with useMemo or useCallback may recalculate unnecessarily without proper keys. Also note that React 18+’s concurrent rendering makes unstable keys more dangerous: partial renders + key mismatches can cause subtle hydration or state corruption bugs. Pro tip: lint with eslint-plugin-react-hooks/exhaustive-deps won’t catch bad keys—but react/jsx-key and react/no-array-index-key rules will.