Lists and Keys
18 minBeginnerReact
In this lesson
- ▸Render an array of data as elements with
array.map() - ▸Give each item a unique, stable
keyand explain what React uses it for - ▸Recognise the missing-key warning and the bugs caused by
key={index}
The big idea
Lists in React are just arrays mapped to elements. The key is each item's name tag — it lets React tell items apart between renders, so use something that belongs to the item, like its id.
Menus, chat messages, search results — most UIs show lists of data. You almost never write each <li> by hand. Instead, you keep the data in an array and use map() to turn each item into an element.
const drinks = [
{ id: "d1", name: "Teh Tarik" },
{ id: "d2", name: "Milo Ais" },
];
<ul>
{drinks.map((drink) => (
<li key={drink.id}>{drink.name}</li>
))}
</ul>JSX can render an array of elements directly, so drinks.map(…) inside {} just works. The new part is key.
Why does React need keys?
When the list changes (an item is added, removed or re-ordered), React compares the new list with the old one. The key tells React which item is which, so it can keep each item's DOM and state attached to the right data — instead of guessing by position.
- key
- A special prop on the element returned from
map(). It must be unique among its siblings and stay the same for the same item across renders. Your component can't read it as a prop. - Stable id
- An identifier that belongs to the data itself — a database id, a product code, a slug. The best key.
The warning you'll see
Forget the key and React's development build prints: Warning: Each child in a list should have a unique "key" prop. Watch for it in the console below the preview — it's telling you about a real bug waiting to happen.
Index as key: the quiet bug
map((item, index) => <li key={index}>…) silences the warning, but the key now means "position 0, position 1…". Remove the first item and every item shifts up a position — React thinks the last item was removed and re-uses the other rows for different data. Anything kept inside those rows (typed text, checkbox state, component state) ends up next to the wrong item.
Breaks when the list changes
{dishes.map((dish, index) => (
<li key={index}>{dish.name}</li>
))}Stable — follows the data
{dishes.map((dish) => (
<li key={dish.id}>{dish.name}</li>
))}- Use an id from your data. If you create items yourself, give them an id when you create them.
- Index is acceptable only for lists that never re-order, filter, or have items added/removed in the middle.
- Never use
Math.random()— a new key every render makes React throw away and rebuild every row each time.
Replace the single hard-coded <li> with dishes.map(…) so all four dishes appear. Keep the same markup for each row (li.dish with .name, .price and the .qty input), show the price with two decimals using dish.price.toFixed(2), and give each <li> a key from the data — the console must show no key warning.
Checks
- All four dishes are listed
- Prices show two decimals
- No missing-key warning in the console
Check understanding
What you learned
- ✓
array.map(item => <li key={item.id}>…</li>)turns data into UI. - ✓Keys let React match items between renders; they must be unique among siblings and stable.
- ✓Missing keys trigger a console warning;
key={index}hides the warning but mixes up state when the list changes.
Console output from your code appears here.