Why is using array indices as keys a bad idea?
ReactThe short answer
Using array indices as keys can cause bugs when the list order changes. React uses keys to track which items have changed, been added, or been removed. If you use indices as keys and the list gets reordered, React will reuse the wrong components, leading to stale state, incorrect data, and visual glitches.
How keys work in React
When you render a list, React needs a way to identify each item so it can efficiently update the DOM. That is what the key prop is for.
// React uses keys to match items between renders{ items.map((item) => ( <ListItem key={item.id} item={item} /> ));}Between renders, React looks at the keys to figure out:
- Which items are new (need to be created)
- Which items are gone (need to be removed)
- Which items moved (need to be reordered)
The problem with index keys
Let's say you have a list of items and use the index as the key:
{ items.map((item, index) => ( <ListItem key={index} item={item} /> ));}Now imagine the list is ["Apple", "Banana", "Cherry"] and the user deletes "Apple". Here is what happens:
Before deletion:
| Index (key) | Item |
|---|---|
| 0 | Apple |
| 1 | Banana |
| 2 | Cherry |
After deletion:
| Index (key) | Item |
|---|---|
| 0 | Banana |
| 1 | Cherry |
React sees that key 0 still exists but its content changed from "Apple" to "Banana". Instead of removing "Apple" and shifting everything, React updates the existing components in place. Key 2 is gone, so React removes what used to be "Cherry" — which is wrong.
A real bug example
The problem becomes very visible when list items have their own state:
function TodoList() { const [todos, setTodos] = useState([ 'Buy milk', 'Walk dog', 'Read book', ]); const removeTodo = (index) => { setTodos(todos.filter((_, i) => i !== index)); }; return ( <ul> {todos.map((todo, index) => ( <TodoItem key={index} text={todo} onRemove={() => removeTodo(index)} /> ))} </ul> );}function TodoItem({ text, onRemove }) { const [checked, setChecked] = useState(false); return ( <li> <input type="checkbox" checked={checked} onChange={() => setChecked(!checked)} /> {text} <button onClick={onRemove}>Remove</button> </li> );}If you check "Buy milk" and then remove it, the checkbox state (which lives in TodoItem) stays with key 0. But key 0 is now "Walk dog." So "Walk dog" shows as checked even though you never checked it.
When index keys are okay
Using index as a key is fine when all three conditions are true:
- The list is static — items are never added, removed, or reordered
- Items have no local state (like form inputs or checkboxes)
- Items do not have unique IDs available
For example, rendering a static list of navigation links is fine:
{ navLinks.map((link, index) => ( <a key={index} href={link.url}> {link.label} </a> ));}What to use instead
Always use a unique, stable identifier:
// Use an ID from the data{ users.map((user) => ( <UserCard key={user.id} user={user} /> ));}// If the data has no ID, generate one when creating the itemconst newTodo = { id: crypto.randomUUID(), text: 'New todo',};Common Pitfalls
Never use Math.random() or Date.now() as a key. These change on every render, so React treats every item as new and destroys and recreates all components. This is worse than using index keys — it defeats the entire purpose of keys.
Interview Tip
When answering this question, use the checkbox example. It is the clearest way to show the bug — a checked item jumps to a different item after deletion. Then explain that the fix is using a unique, stable ID. If the interviewer asks when index keys are acceptable, knowing the three conditions shows you understand the topic deeply rather than just following a rule.
Why interviewers ask this
This question tests if you understand how React's reconciliation works. Many candidates know "do not use index as key" but cannot explain why. Interviewers want to see if you understand the actual mechanism — how React uses keys to match elements between renders and what goes wrong when keys do not uniquely identify items. It also tests if you know when the rule does not apply.