Reconciliation and keys: how React decides what to keep
React's diffing rules: a different type remounts, the same type updates, and list items are matched by key. See why index keys attach state to the wrong row, and how a key resets a component.
Comes up in: React, Recruiter screen
Learn#
Vivek’s to-do app has a note field on every row. When he deletes the first task, the next task shows the deleted task’s note. The data is right; the screen is wrong.
Reconciliation is how React turns a new render into DOM changes, by comparing new elements with the old ones (diffing). In lists, it matches items by key. With key={index}, removing the first item shifts every key, so React gives the old first row’s state to the new first item:
import { GlobalRegistrator } from "@happy-dom/global-registrator";
GlobalRegistrator.register(); // a DOM for Node; in a browser you already have one
globalThis.IS_REACT_ACT_ENVIRONMENT = true;
const { createElement: h, useState, act } = await import("react");
const { createRoot } = await import("react-dom/client");
function Row({ label }) {
const [draft] = useState(`draft for ${label}`); // state set once, on mount
return h("li", null, `${label}: ${draft}`);
}
function List({ items, keyBy }) {
return h("ul", null, items.map((label, i) => h(Row, { key: keyBy === "index" ? i : label, label })));
}
for (const keyBy of ["index", "id"]) {
const box = document.createElement("div");
const root = createRoot(box);
await act(() => root.render(h(List, { items: ["Asha", "Ravi", "Meera"], keyBy })));
await act(() => root.render(h(List, { items: ["Ravi", "Meera"], keyBy }))); // remove the first row
console.log(`${keyBy} keys →`, [...box.querySelectorAll("li")].map((li) => li.textContent).join(" | "));
}Output (verified)
index keys → Ravi: draft for Asha | Meera: draft for Ravi id keys → Ravi: draft for Ravi | Meera: draft for Meera
State
- key 0: Asha (draft for Asha)
- key 1: Ravi (draft for Ravi)
- key 2: Meera (draft for Meera)
Before: three rows with index keys. Each Row keeps its own draft state.
Read the steps as text
- Before: three rows with index keys. Each Row keeps its own draft state.
- Asha is removed. The new list is Ravi, Meera, so their keys are now 0 and 1.
- React matches by key: key 0 still exists, so it updates the old Asha row with label Ravi, keeping Asha's state.
- With id keys, Asha's row is removed and the others keep their own state.
Predict#
Predict first
A component renders <input> when editing and <textarea> otherwise, at the same place. What happens to typed text when it switches?
Different types are never matched; React destroys the old subtree, with its state and DOM, and builds the new one. The same rule explains why defining a component inside another component resets its state on every render: it is a new type each time.
Interview angle#
Say it like this — about 30 seconds
“Reconciliation compares the new element tree with the previous one using simple rules. If the type at a position changes, React unmounts the old subtree and mounts a new one. If the type is the same, it keeps the instance and updates its props. In lists, children are matched by key, so keys must be stable and unique among siblings. Index keys break when items are inserted, removed or reordered: state and DOM attach to the wrong item. Changing a key forces a reset.”
Follow-up How does React's reconciliation algorithm work?
Follow-up Why are keys important, and what goes wrong with array indexes?
Follow-up How would you force a component to reset its state?
<Profile key={userId} />: React mounts a fresh instance.Practice#
Guided
Implement React’s matching rules for one level of children.
Done when
- Same key and same type is an update; anything else is a mount.
- Missing keys fall back to the index.
- Old children that are not updated are listed for unmounting, in their old order.
Remember#
Try to answer each card before you open it. Then add them to your reviews.
What does React do when the element type at a position changes?
Unmounts the old subtree and mounts a new one; state is lost.
Why are index keys risky?
Inserts, removals and reorders shift keys, so state attaches to the wrong item.
How do you reset a component's state on purpose?
Change its key.
Must keys be unique across the whole app?
No, only among siblings in the same list.
Go deeper
Four layers. Stop at the one your interview needs; each ends with a quick check.
The core ideaEvery round
Check yourself: When are index keys acceptable?
When the list never reorders, filters or has items inserted or removed, and rows have no state.
How it works underneathSenior rounds
Check yourself: Why does a component defined inside another lose its state each render?
A new function is created each render, so its type changes and React remounts it.
Edge cases and trapsWhere people slip
Check yourself: Does a key change in the same position remount even with the same type?
Yes. A new key is a new identity.
In productionStaff-level answers
Keep keys stable across renders: never generate them during render. For lists without ids, create ids when the data is created or loaded. Big lists also need virtualization (RCT.11.02).
Check yourself: What does React warn about in development for lists?
Missing keys and duplicate keys among siblings.
Finished the five steps? Mark it, and its cards join your reviews.
Last checked 2026-11-01. Spot a mistake? Use “Report an error” below — fixes are listed on the corrections page.
Interview questions this answers
- How does React's reconciliation algorithm work?
- Why are keys important? What goes wrong with array indexes as keys?
- How would you force a component to reset its state?