Ojasa Mirai

Ojasa Mirai

ReactJS

Loading...

Learning Level

🟒 BeginnerπŸ”΅ Advanced
πŸ“‹ Rendering Lists with map()πŸ”‘ Keys and Reconciliation✨ Unique Keys⚠️ Common Key MistakesπŸ” Filtering Lists↕️ Sorting and Reorderingβž• Dynamic Lists
Reactjs/Lists Keys/Common Key Mistakes

⚠️ Common Key Mistakes

Mistake #1: Using Index as Key in Dynamic Lists

The Problem

// ❌ WRONG - Using index in a list that can reorder
function TodoList() {
  const [todos, setTodos] = React.useState([
    { id: 1, text: "Buy milk" },
    { id: 2, text: "Walk dog" }
  ]);

  const addTodo = (text: string) => {
    // Adding to the beginning!
    setTodos([{ id: Math.random(), text }, ...todos]);
  };

  return (
    <ul>
      {todos.map((todo, index) => (
        <li key={index}>  // ❌ Index changes when items are added
          <input type="checkbox" />
          {todo.text}
        </li>
      ))}
    </ul>
  );
}

What Goes Wrong

1. First render: `key=0` points to "Buy milk", `key=1` points to "Walk dog"

2. You add a new item at the beginning

3. Now `key=0` points to the new item, but React thinks it's the same as before

4. Component state (like that checkbox) gets attached to the wrong item

The Fix

// βœ… CORRECT - Use stable ID
function TodoList() {
  const [todos, setTodos] = React.useState([
    { id: 1, text: "Buy milk" },
    { id: 2, text: "Walk dog" }
  ]);

  const addTodo = (text: string) => {
    setTodos([{ id: Date.now(), text }, ...todos]);  // Each ID is unique
  };

  return (
    <ul>
      {todos.map((todo) => (
        <li key={todo.id}>  // βœ… Stable ID that won't change
          <input type="checkbox" />
          {todo.text}
        </li>
      ))}
    </ul>
  );
}

Mistake #2: Random Keys

The Problem

// ❌ WRONG - Generating key with Math.random()
function MessageList() {
  const messages = ["Hello", "World", "React"];

  return (
    <ul>
      {messages.map((message) => (
        <li key={Math.random()}>  // ❌ New key every render!
          {message}
        </li>
      ))}
    </ul>
  );
}

Why It's Bad

Every time the component re-renders:

  • React gets new random keys
  • React thinks all items are different
  • React recreates all DOM nodes
  • Component state is lost
  • Animations restart
  • Performance suffers

The Fix

// βœ… CORRECT - Generate ID once, not per render
function MessageList() {
  const [messages] = React.useState(() =>
    ["Hello", "World", "React"].map((msg, idx) => ({
      id: idx,  // Or use uuidv4() in real apps
      text: msg
    }))
  );

  return (
    <ul>
      {messages.map((message) => (
        <li key={message.id}>  // βœ… Same key every render
          {message.text}
        </li>
      ))}
    </ul>
  );
}

Mistake #3: Unstable Composite Keys

The Problem

// ❌ WRONG - Creating key from changing values
function UserItems() {
  const [order, setOrder] = React.useState("asc");

  const items = [
    { id: 1, name: "Alice", score: 100 },
    { id: 2, name: "Bob", score: 85 },
    { id: 3, name: "Carol", score: 92 }
  ];

  const sorted = order === "asc"
    ? [...items].sort((a, b) => a.score - b.score)
    : [...items].sort((a, b) => b.score - a.score);

  return (
    <div>
      <button onClick={() => setOrder(order === "asc" ? "desc" : "asc")}>
        Sort {order}
      </button>
      <ul>
        {sorted.map((item, index) => (
          <li key={`${item.name}-${index}`}>  // ❌ Index changes when sorting!
            {item.name}: {item.score}
          </li>
        ))}
      </ul>
    </div>
  );
}

The Fix

// βœ… CORRECT - Use stable ID regardless of sort order
function UserItems() {
  const [order, setOrder] = React.useState("asc");

  const items = [
    { id: 1, name: "Alice", score: 100 },
    { id: 2, name: "Bob", score: 85 },
    { id: 3, name: "Carol", score: 92 }
  ];

  const sorted = order === "asc"
    ? [...items].sort((a, b) => a.score - b.score)
    : [...items].sort((a, b) => b.score - a.score);

  return (
    <div>
      <button onClick={() => setOrder(order === "asc" ? "desc" : "asc")}>
        Sort {order}
      </button>
      <ul>
        {sorted.map((item) => (
          <li key={item.id}>  // βœ… ID stays the same regardless of order
            {item.name}: {item.score}
          </li>
        ))}
      </ul>
    </div>
  );
}

Mistake #4: Missing Keys Entirely

The Problem

// ❌ WRONG - No key at all
function ItemList() {
  const items = ["React", "Vue", "Angular"];

  return (
    <ul>
      {items.map((item) => (
        <li>{item}</li>  // ❌ React uses index as fallback key
      ))}
    </ul>
  );
}

Without a key, React falls back to using the index. This causes all the problems we discussed above.

The Fix

// βœ… CORRECT - Always provide a key
function ItemList() {
  const items = [
    { id: 1, name: "React" },
    { id: 2, name: "Vue" },
    { id: 3, name: "Angular" }
  ];

  return (
    <ul>
      {items.map((item) => (
        <li key={item.id}>{item.name}</li>  // βœ… Explicit key
      ))}
    </ul>
  );
}

<details><summary>πŸ“š More Examples</summary>

Mistake #5: Keys That Depend on Props

// ❌ WRONG - Key depends on parent prop
interface ListProps {
  baseId: string;
  items: string[];
}

function BadKeyList({ baseId, items }: ListProps) {
  return (
    <ul>
      {items.map((item, index) => (
        <li key={`${baseId}-${index}`}>  // ❌ baseId changes = key changes
          {item}
        </li>
      ))}
    </ul>
  );
}

// If baseId changes, all keys change even though items are the same!

// βœ… CORRECT
function GoodKeyList({ baseId, items }: ListProps) {
  const itemList = items.map((item, idx) => ({
    id: idx,  // Or get real IDs from data
    value: item
  }));

  return (
    <ul>
      {itemList.map((item) => (
        <li key={item.id}>  // βœ… Independent of props
          {item.value}
        </li>
      ))}
    </ul>
  );
}

Real-World Example: Filtering Issues

// ❌ WRONG - Index changes when filtering
function ContactsList() {
  const [filter, setFilter] = React.useState("");
  const [contacts, setContacts] = React.useState([
    { id: 1, name: "Alice", email: "alice@example.com" },
    { id: 2, name: "Bob", email: "bob@example.com" },
    { id: 3, name: "Carol", email: "carol@example.com" }
  ]);

  const filtered = contacts.filter(c =>
    c.name.toLowerCase().includes(filter.toLowerCase())
  );

  return (
    <div>
      <input
        value={filter}
        onChange={(e) => setFilter(e.target.value)}
        placeholder="Filter..."
      />
      <ul>
        {filtered.map((contact, index) => (
          <li key={index}>  // ❌ When filtered, indices change
            <EditableContact contact={contact} />
          </li>
        ))}
      </ul>
    </div>
  );
}

// βœ… CORRECT
function CorrectContactsList() {
  const [filter, setFilter] = React.useState("");
  const [contacts, setContacts] = React.useState([
    { id: 1, name: "Alice", email: "alice@example.com" },
    { id: 2, name: "Bob", email: "bob@example.com" },
    { id: 3, name: "Carol", email: "carol@example.com" }
  ]);

  const filtered = contacts.filter(c =>
    c.name.toLowerCase().includes(filter.toLowerCase())
  );

  return (
    <div>
      <input
        value={filter}
        onChange={(e) => setFilter(e.target.value)}
        placeholder="Filter..."
      />
      <ul>
        {filtered.map((contact) => (
          <li key={contact.id}>  // βœ… ID stays stable when filtering
            <EditableContact contact={contact} />
          </li>
        ))}
      </ul>
    </div>
  );
}

</details>


Summary: Key Mistakes and Fixes

MistakeExampleProblemFix
Index in dynamic list`key={index}`State gets shuffledUse unique ID
Random key`key={Math.random()}`Key changes every renderStore ID in state
Unstable composite`key={name + index}`Changes when sortedUse stable ID only
No key(no key prop)Falls back to indexAlways add key
Key from prop`key={parentId + index}`Changes with parentUse item's own ID

βœ… Key Takeaways

1. βœ… Never use index as key for lists that can reorder, filter, or change

2. βœ… Never generate keys with Math.random() or similar functions

3. βœ… Keys must be the same across all renders for the same item

4. βœ… Always include a key prop, especially with dynamic lists

5. βœ… Use unique IDs from your dataβ€”database IDs are best

6. βœ… Composite keys should combine stable values only

7. βœ… Don't base keys on props that change

8. βœ… The key must identify the item, not its position

9. βœ… When in doubt, use the item's ID from your data source

10. βœ… Bad keys don't cause errors but cause subtle bugs in component state


πŸŽ“ Next Steps

Now let's look at how to filter lists correctly without breaking your keys.

β†’ Learn about Filtering Lists

Challenge: Fix broken keys in a list


Resources

Python Docs

Ojasa Mirai

Master AI-powered development skills through structured learning, real projects, and verified credentials. Whether you're upskilling your team or launching your career, we deliver the skills companies actually need.

Learn Deep β€’ Build Real β€’ Verify Skills β€’ Launch Forward

Courses

PythonFastapiReactJSCloud

Β© 2026 Ojasa Mirai. All rights reserved.

TwitterGitHubLinkedIn