Frontend Master

JavaScript Curriculum

Lists & Keys
+50 XP

Lists & Keys

easy
~25 min·50 XP

The coffee shop menu has dozens of items. Instead of writing a MenuCard for each one, you map over the items array and render one component per item. When the barista adds a special, the list updates with one state change.

Lists & Keys

The .map() method is React's primary tool for rendering lists. The key prop is not optional — it is how React tracks which items changed across renders, enabling efficient updates and preventing subtle bugs.

Four List Rendering Patterns

From basic to filter+map and Fragment lists:

list-rendering.jsx
const items = [
  { id: 1, name: 'Espresso',   price: 2.50 },
  { id: 2, name: 'Cappuccino', price: 3.50 },
]

function Menu() {
  return (
    <div className="menu">
      {items.map(item => (
        <MenuCard
          key={item.id}
          name={item.name}
          price={item.price}
        />
      ))}
    </div>
  )
}
💡 Use item.id as key — a stable, unique identifier. Never use the array index as key when the list can be reordered or filtered.
Live — filter + map
Espresso£2.50
Cappuccino£3.50
Croissant£2.00
Cold Brew£3.50
Matcha£4.00
5 of 5 items · key=id
ℹ️key must be on the outermost element from map
If `.map()` returns a component, key goes on the component: `<MenuCard key={item.id} />`. If it returns a Fragment, use the explicit form: `<Fragment key={item.id}>`. The key must be unique among siblings — not globally.

Why Keys Matter — Stable vs Unstable

See the difference between key={item.id} and key={index}:

key-prop.jsx
Key strategy:
✓ stable keys
Espressokey="a"
Cappuccinokey="b"
Cold Brewkey="c"
// Reorder or add/remove items to see key behavior
key=id ✓
React matches nodes by identity. Reorder moves the DOM node. Remove deletes only that node.
key=index ⚠
React matches by position. Reorder destroys and recreates. Can cause bugs with state, animations, and focus.
⚠️Never use array index as key for dynamic lists
Index keys cause bugs when items are reordered, filtered, or removed. React matches by position not identity — it destroys and recreates DOM nodes unnecessarily. State attached to a component (like input values) gets mixed up between items. Use a stable ID from your data.

Dynamic List — Full CRUD

Add, toggle, delete, filter — key={id} throughout:

dynamic-list.jsx2 left
Priority:
Buy coffee beanskey=1
Fix the espresso machinekey=2
Update menu boardkey=3
💡Derive don't duplicate
Never store `filteredItems` in useState. Derive it: `const visible = items.filter(...)`. It recomputes on every render when items or filter changes — automatically, with no synchronisation bugs.

Your Challenge

Build a menu with filter buttons (All / Coffee / Food / Tea). State: items array and category string. Derive: visible = items.filter(i => category === 'all' || i.category === category). Render: visible.map(item => <MenuCard key={item.id} {...item} />). Add a count: {visible.length} items.

Challenge

Build a filterable menu list: items array in state, filter state ('all'/'coffee'/'food'). Derive visible = items.filter(...).map(...). Add, remove, and reorder items. Use item.id as key — never the array index.

mapkey-proplist-renderingfilterstable-keysindex-key-bugFragment-keydynamic-listsarray-state
Lists & Keys | Nexus Learn