Skip to main content

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:

  1. The new item gets index 0.
  2. The old item 0 becomes index 1.
  3. React compares Key 0 (old) with Key 0 (new).
  4. 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} />
))}
When is Index as Key Acceptable?

Only when all three conditions are met:

  1. The list and items are completely static (never filtered, sorted, or mutated).
  2. Items have no internal state (pure presentational text/display).
  3. The list is never reordered.

4. Rules of Keys​

  1. 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.
  2. Keys must not change across renders: Never generate keys on the fly during render (e.g. key={Math.random()} or key={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 key prop.
  • 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.