"Each Child in a List Should Have a Unique Key Prop": What It Means
React's key warning appears when you render a list without telling React which item is which. Why keys matter, why array index is a bad key for lists that change, what to use instead, and how to fix the warning in fragments and nested maps.
Warning: Each child in a list should have a unique "key" prop.
Check the render method of `TodoList`.
This is React's most common warning. It's only a warning — the page still renders — but ignoring it leads to genuinely confusing bugs later.
What React is asking for
When you render a list:
{todos.map(todo => <TodoItem todo={todo} />)}
React needs to know which item is which between renders. If the list changes — an item is added at the top, one is deleted, the order changes — React uses the key to match old items to new ones, so it can update only what changed and keep each item's state attached to the right one.
Give each item a stable, unique key:
{todos.map(todo => <TodoItem key={todo.id} todo={todo} />)}
What to use as a key
Best: an ID from your data. A database ID, a UUID, a slug — anything that uniquely identifies the item and doesn't change. (UUID vs auto-increment)
OK: something naturally unique. An email address in a list of users, a date in a calendar.
Risky: the array index.
{todos.map((todo, index) => <TodoItem key={index} todo={todo} />)}
This silences the warning, but it tells React "item 0 is whatever's first." If you delete the first item, every item's key shifts by one, and React thinks the last item was deleted and every other item changed. Any state inside the items — a half-typed input, a checkbox, an open dropdown — ends up attached to the wrong row.
Index is acceptable only when the list never reorders, filters or has items inserted — a static list of footer links, say.
Never: random values.
key={Math.random()} // ❌
A new key every render means React throws away and rebuilds every item every time. Inputs lose focus, animations restart, performance drops.
Where the key goes
On the outermost element returned from map — not on something inside it:
// ❌ key is on the inner element
{users.map(user => (
<div>
<UserCard key={user.id} user={user} />
</div>
))}
// ✅
{users.map(user => (
<div key={user.id}>
<UserCard user={user} />
</div>
))}
Fragments need keys too
The short <>...</> syntax can't take a key. Use the long form:
import { Fragment } from 'react'
{items.map(item => (
<Fragment key={item.id}>
<dt>{item.term}</dt>
<dd>{item.definition}</dd>
</Fragment>
))}
Keys only need to be unique among siblings
Two different lists can use the same IDs. Keys only have to be unique within one map. If your data has duplicate IDs in the same list — a sign of a data bug — you'll get a "two children with the same key" warning instead.
Your data has no IDs
Generate them when the data is created, not when it's rendered:
const newTodo = { id: crypto.randomUUID(), text }
setTodos([...todos, newTodo])
Keys as a reset button
Changing a component's key makes React treat it as a brand-new component, resetting all its state. It's a handy trick: <ProfileForm key={user.id} user={user} /> resets the form when you switch users. (useState explained)
The summary
- Keys tell React which list item is which between renders.
- Use a stable ID from your data.
- Index keys break state when lists reorder; random keys break everything.
- Put the key on the outermost element in the
map; use<Fragment key>for fragments.
EasySpawn runs your app and Claude Code on the same persistent server, so you can ask it to clean up every console warning and check the result in a live preview. See how it works or join the waitlist.
Related: useState Explained · JavaScript Array Methods · What Is React? · Browser Developer Tools for Beginners
Keep reading
"Unexpected Token < in JSON at Position 0": What It Means and How to Fix It
Your code expected JSON and got HTML — almost always an error page or your app's index.html. Why it happens (wrong URL, 404, server error, SPA fallback, login redirect), how to see what the server actually sent, and how to parse responses safely.
React "Too Many Re-renders" and "Maximum Update Depth Exceeded": Fixes
Both errors mean a component keeps updating state, which re-renders it, which updates state again — forever. The four patterns that cause it (calling a handler instead of passing it, setState during render, effects without dependencies, objects in dependency arrays) and their fixes.