All visualizationsReact · 8 of 18
key={index} — the bug that puts Ravi’s number under Priya’s name
Build React’s row-matching rule, run the famous list corruption for real, then fix it with one change.
💡
THE BIG IDEA
Every React list demands a key, most tutorials shrug and write key={index}, and one day a deleted row’s text appears under the wrong name. Instead of warning you about this bug, we run it: a miniature of React’s actual match-by-key contract, executed twice — once keyed by position (watch the corruption happen), once keyed by identity (watch it become impossible).
Move your mouse over any line to see what it does. Hover a loop line and it plays through every repeat. Or press ▶ Play to watch the whole thing. On a phone, tap the arrows.
1function reconcile(oldRows, items, keyOf) {
2 return items.map((item, i) => {
3 const key = keyOf(item, i);
4 const old = oldRows.find((r) => r.key === key);
5 const row = old || { key, typed: "" };
6 row.label = item;
7 return row;
8 });
9}
10let rows = [];
11const render = (items, keyOf) => { rows = reconcile(rows, items, keyOf); };
12render(["Ravi", "Priya"], (item, i) => i);
13rows[0].typed = "98765";
14render(["Priya"], (item, i) => i);
15console.log("index key:", rows[0].label, "shows", JSON.stringify(rows[0].typed));
16rows = [];
17render(["Ravi", "Priya"], (item) => item);
18rows[0].typed = "98765";
19render(["Priya"], (item) => item);
20console.log("stable key:", rows[0].label, "shows", JSON.stringify(rows[0].typed));
A contact list: two rows, each with a text box. You type Ravi’s number into row 1, delete Ravi… and his number is now sitting under PRIYA’s name. Let’s catch this famous bug red-handed.
This is the key={index} corruption — asked in almost every React interview. We build React’s row-matching rule ourselves and run the crime scene twice: once with index keys (bug), once with stable keys (fixed).
📦 Memory boxes
what the program is remembering right now
nothing remembered yet
🖥️ What the computer shows
the answers the program prints out
nothing yet
1/13
UP NEXT IN REACT
React.lazy & Suspense — the 80kb nobody asked for
A download ledger proves it: 20kb first paint, and the chart chunk ships only when someone actually opens Reports.
JSX under the hood — HTML’s clothes, JavaScript’s bodyReact.lazy & Suspense — the 80kb nobody asked for