2.6 Lists & Keys
← Back to Chapter 2: React Fundamentals
Displaying dynamic collections of data (such as product cards, comment threads, or search results) is a core task in web applications. In React, you transform arrays of data into arrays of elements using JavaScript's .map() method, assigning each item a unique key.
1. Rendering Lists with map()
const frameworkList = [
{ id: "f1", name: "React", type: "Frontend Library" },
{ id: "f2", name: "Next.js", type: "Full-Stack Framework" },
{ id: "f3", name: "Vite", type: "Build Tool" }
];
function FrameworkCatalog() {
return (
<ul className="framework-list">
{frameworkList.map(framework => (
<li key={framework.id} className="framework-item">
<strong>{framework.name}</strong> — <span>{framework.type}</span>
</li>
))}
</ul>
);
}
2. Why React Demands key
When an array re-renders (elements are added, removed, reordered, or edited), React needs to determine which items changed, were added, or were removed without blindly re-creating every single DOM node.
The key prop serves as a stable, unique identity for an element across renders.
graph TD
subgraph Render 1
A1["Key: 'a' (Item A)"]
B1["Key: 'b' (Item B)"]
C1["Key: 'c' (Item C)"]
end
subgraph Render 2 [Inserted New Item at Start]
D2["Key: 'd' (New Item D)"]
A2["Key: 'a' (Item A - Reused!)"]
B2["Key: 'b' (Item B - Reused!)"]
C2["Key: 'c' (Item C - Reused!)"]
end
Render 1 -. "With Keys: React only creates D and preserves A, B, C DOM nodes" .-> Render 2
3. The Index as Key Anti-Pattern
Using the array index as a key (key={index}) is dangerous and leads to subtle UI bugs and performance degradation:
// ❌ DANGEROUS: Using index as key!
{todos.map((todo, index) => (
<TodoItem key={index} text={todo.text} />
))}
Why Index as Key Breaks
If you prepend a new item to the start of the list:
- The new item gets index
0. - The old item
0becomes index1. - React compares
Key 0(old) withKey 0(new). - Any uncontrolled internal state (like
<input>values, animations, or checkboxes) remains attached to the wrong item!
// ✅ SAFE: Use stable, unique IDs from database or backend
{todos.map(todo => (
<TodoItem key={todo.id} text={todo.text} />
))}
Only when all three conditions are met:
- The list and items are completely static (never filtered, sorted, or mutated).
- Items have no internal state (pure presentational text/display).
- The list is never reordered.
4. Rules of Keys
- Keys must be unique among siblings: Elements in the same array must have distinct keys, but keys do not need to be globally unique across different arrays or components.
- Keys must not change across renders: Never generate keys on the fly during render (e.g.
key={Math.random()}orkey={crypto.randomUUID()}inside the.map()). This forces React to destroy and rebuild the DOM node on every single render!
5. Summary Checklist
- Use
array.map()to transform data collections into JSX elements. - Every child element rendered in a list must have a unique, stable
keyprop. - Keys enable React's reconciliation algorithm to efficiently match existing DOM nodes.
- Avoid using array indices as keys whenever lists can be sorted, filtered, or mutated.
- Never generate random keys inside render functions.