← Back to Chapters

Index as Key

⚛️ Index as Key

⚡ Quick Overview

In React, every item rendered in a list should have a unique key. This helps React efficiently update, add, or remove list items in the DOM without breaking UI or state.

A common shortcut is to use the array index as the key (for example, key={index}). While this might seem to “work”, it can create subtle bugs when items are added, removed, or reordered.

Understanding when index keys are safe—and when they are dangerous—is important for building predictable, stable React components.

? Core idea: Prefer stable, unique IDs over array indexes.

? Key Concepts

  • Keys identify list items — React uses them to match old and new elements between renders.
  • Array index keys change when the list changes — removing or reordering items shifts indexes.
  • Unstable keys break assumptions — React may reuse DOM nodes for the “wrong” item.
  • Stable IDs keep state aligned — each logical item always maps to the same key.
  • Index as key is only safe for short, static, purely presentational lists.

? Syntax & Theory of React Keys

When rendering a list in React, you typically write something like:

{items.map(item => (<li key={item.id}>{item.label}</li>))}

  • key must be unique among siblings.
  • Keys are not passed as props to the component; they are only used internally by React.
  • Keys should be stable over time — the same logical item keeps the same key between renders.
  • If keys change incorrectly, React may preserve or reset component state in the wrong place.

? Code Examples

? Example 1: Using Index as Key

Here’s a simple list where the array index is used as the key:

? View Code Example
// Using index as key in a simple list (safe only when list is static)
function NameList() {
  const names = ["Alice", "Bob", "Charlie"];

  return (
    <ul>
      {names.map((name, index) => (
        <li key={index}>{name}</li>
      ))}
    </ul>
  );
}

This component works correctly as long as the list is static and never changes. But as soon as you add, remove, or reorder items, using index as the key can introduce mismatches between items and their internal state.

? Example 2: Reordering or Removing Items with Index Keys

Consider a list of editable inputs where each item uses its index as the key:

? View Code Example
// Using index as key in a dynamic list of inputs (dangerous)
function EditableList() {
  const [items, setItems] = React.useState(["Apple", "Banana", "Cherry"]);

  const removeItem = (indexToRemove) => {
    setItems(items.filter((_, index) => index !== indexToRemove));
  };

  return (
    <ul>
      {items.map((item, index) => (
        <li key={index}>
          <input defaultValue={item} />
          <button onClick={() => removeItem(index)}>❌</button>
        </li>
      ))}
    </ul>
  );
}

? Live Behavior / Explanation

  • You type custom values into each input.
  • Then you remove an item from the middle of the list.
  • Because keys are based on indexes, React reuses DOM nodes for the next items.
  • Result: input values appear to “jump” up or get swapped — the shown text no longer matches the underlying data.

This happens because React assumes items with the same key are the “same” item between renders. When keys shift due to index-based keys, that assumption breaks.

? Visualizing the Index Key Problem

For a list ["A", "B", "C"] with index keys [0, 1, 2]:

  • Removing “A” means “B” now appears at index 0 and “C” at index 1.
  • React still sees keys [0, 1] and reuses the underlying DOM nodes.
  • State/input values belonging to “B” may appear attached to “C”, and so on.

The UI still renders, but the component state no longer matches the logical data, causing confusing bugs.

✅ Example 3: Using Stable Unique IDs as Keys

The recommended approach is to give each item a stable, unique identifier (such as an id field) and use that as the key:

? View Code Example
// Using a stable id for each item keeps inputs and state aligned
function SafeList() {
  const [fruits, setFruits] = React.useState([
    { id: 1, name: "Apple" },
    { id: 2, name: "Banana" },
    { id: 3, name: "Cherry" },
  ]);

  return (
    <ul>
      {fruits.map((fruit) => (
        <li key={fruit.id}>
          <input defaultValue={fruit.name} />
        </li>
      ))}
    </ul>
  );
}

Now, even if you insert, remove, or reorder items, each fruit keeps the same id and therefore the same key, so React preserves the correct state for each list item.

⚙️ Example 4: When It’s Safe to Use Index as Key

Using the array index as a key is acceptable in a few specific cases:

  • The list is static and its items never change order.
  • The items are purely presentational (no inputs or component state).
  • Re-render performance and state correctness are not critical.
? View Code Example
// Safe: static, read-only list using index as key
const colors = ["Red", "Green", "Blue"];

<ul>
  {colors.map((color, index) => (
    <li key={index}>{color}</li>
  ))}
</ul>

? Example 5: Dynamic Lists with Generated IDs

For dynamic lists like todos or form rows, generate a unique ID when the item is created (for example, using Date.now() or a UUID library) and keep using that ID as the key:

? View Code Example
// Dynamic todo list using Date.now() to generate stable ids
function TodoList() {
  const [todos, setTodos] = React.useState([
    { id: Date.now(), task: "Learn React" },
  ]);

  const addTodo = () => {
    const newTodo = { id: Date.now(), task: "New Task" };
    setTodos([...todos, newTodo]);
  };

  return (
    <div>
      <ul>
        {todos.map((t) => (
          <li key={t.id}>{t.task}</li>
        ))}
      </ul>
      <button className="btn btn-primary" onClick={addTodo}>Add</button>
    </div>
  );
}

? Live Output / Explanation

  • Each todo is created with a unique id at the moment of creation.
  • React uses t.id as the key, so each list item’s DOM and state are stable.
  • Adding or removing todos does not affect the identity of existing items.
  • UI behaves predictably, even in complex forms or interactive lists.

? Index vs Unique ID: Comparison

Scenario Index as Key Unique ID as Key
Static list (no changes) ✅ Safe ✅ Safe
Dynamic list (add/remove) ❌ Can cause UI/state issues ✅ Preserves stability
Reordering elements ❌ Risk of mismatched items ✅ React reuses components correctly
Performance & state consistency ⚠️ Unstable, can cause subtle bugs ✅ Reliable, predictable behavior

? Tips & Best Practices

  • Use index keys only when list order and content are guaranteed to be stable.
  • For dynamic lists (forms, todos, editable inputs), always use unique, stable IDs.
  • Remember: changing a key resets component state — useful when you intentionally want a fresh component.
  • React won’t necessarily warn you about bad keys, so always test dynamic behavior carefully.
  • Avoid using values that can change as keys (like array index or non-unique labels).

? Try It Yourself

  1. Build two lists — one using key={index} and another using key={item.id}. Reorder items and compare how state behaves.
  2. Create a dynamic form with editable inputs and index keys; then remove items from the middle and observe how the input values move around.
  3. Implement a small to-do app using Date.now() or UUIDs as keys and confirm that state stays attached to the correct items.
  4. Use React DevTools “Highlight updates” and see how different key strategies affect rendering behavior.

Goal: Develop an intuition for when index keys are safe and how stable, unique keys improve React’s rendering accuracy and user experience.