Keys (key) and rendering
React compares list items by their keys (key) to understand which items in the list stayed the same and which were added, removed, or reordered, and thereby update the DOM efficiently, without recreating the entire list.
Put simply:
When you have a list of items (for example, via .map()), React needs to figure out:
"Which of the new elements corresponds to which old one?"
For this it needs a unique identifier: key. Without a key, React will simply match elements by position (0th with 0th, 1st with 1st, and so on), which can lead to unexpected re-renders and bugs.
Example without keys
function List() {
const [items, setItems] = useState(['A', 'B', 'C']);
return (
<ul>
{items.map(item => <li>{item}</li>)}
</ul>
);
}If we now change the array to:
['B', 'A', 'C']React will compare the elements by index:
| Old tree | New tree | React's decision |
|---|---|---|
| A (index 0) | B (index 0) | replace A → B |
| B (index 1) | A (index 1) | replace B → A |
| C (index 2) | C (index 2) | keep |
As a result, React will remove both <li> elements and create new ones, even though the elements really just swapped places.
Example with keys
<ul>
{items.map(item => <li key={item}>{item}</li>)}
</ul>Now React compares by key:
| Old tree | New tree | React's decision |
|---|---|---|
| key="A" | key="B" | remove A, add B |
| key="B" | key="A" | remove B, add A |
| key="C" | key="C" | keep |
But thanks to key, React understands that elements A and B already exist and simply swapped places, so it doesn't recreate them, it just reorders them.
Why this matters
Without keys, React:
- loses the connection between old and new elements;
- resets the state of child components (for example, an input loses focus);
- performs unnecessary DOM updates (slower);
- may cause visual bugs (for example, flickering).
How React uses key during diffing
During reconciliation, React walks through the list:
- Compares the old and new tree.
- Uses key to figure out whether an element matches an old node.
- If key matches, it reuses the element (only updates props).
- If key is new, it creates the element.
- If key disappeared, it removes the element.
Example with state in a list
function TodoList({ todos }) {
return (
<ul>
{todos.map(todo => (
<li key={todo.id}>
<input type="checkbox" checked={todo.done} />
{todo.text}
</li>
))}
</ul>
);
}If each todo has a unique id, React:
- keeps the checked state through reorderings;
- doesn't recreate the whole
<li>; - simply updates the changed fields.
If you don't set keys, then when the order changes:
- React recreates all the
<li>elements; - resets all the inputs;
- and the UI "flickers".
Rules for key
| Rule | Why |
|---|---|
| key must be unique among siblings | So React can tell elements apart |
| Stable (doesn't change between renders) | Otherwise React thinks the element is new |
| Don't use the array index as the key | It changes when elements are reordered |
| Better to use a unique id from the data | Guarantees correct behavior |
Summary
| Why keys are needed | What React does |
|---|---|
| Identify list items | Help React "understand" what changed |
| Speed up reconciliation | React updates only the necessary nodes |
| Preserve the state of child components | Focus, input, checkboxes, etc. are not lost |
| Without keys, React compares by index | Causes unnecessary re-renders and bugs |
Short Answer
Interview readyA concise answer to help you respond confidently on this topic during an interview.