Skip to main content

Lists and key

A list is rendered by mapping an array to elements: items.map((item) => <Item key={item.id} item={item} />). key tells React which item is which between renders: it matches old and new children by key, so it can move an item together with its DOM node and state instead of recreating it. A key must be stable (an item keeps its key) and unique among siblings. An ID from the data is the usual choice; the array index is safe only for a static list: never reordered, filtered or added to at the top.

Applies to: React 19.3.

Details​

Rules​

  • The key goes on the element returned from map: <Todo key={id} />, not on the <li> inside Todo.
  • It must be unique only among the siblings of one parent. Two different lists can use the same keys.
  • key is not a prop: the component can't read props.key. If it needs the ID, pass it again as another prop.
  • A key is converted to a string, so 1 and '1' are the same key.
  • Without a key React warns ("Each child in a list should have a unique "key" prop") and matches the items by index.
  • With duplicate keys React warns, and items can be duplicated or lost on update.
  • Several elements per item without a wrapper: <Fragment key={id}>. The short syntax <> can't take a key; see Fragments.

Choosing a Key​

SourceFitsWhy
ID from the databaseYesStable and unique
ID generated when the item is created (crypto.randomUUID())YesStored with the item, so it does not change
Content (key={name})If it is unique and constantEditing the content remounts the item
IndexOnly for a static listShifts on insert, removal, sorting and filtering
Math.random() or crypto.randomUUID() called in renderNoA new key on every render: every item remounts each time

Index as a Key​

  • React keeps the state of a component and its DOM node (the value of an uncontrolled input, focus, scroll position, a running animation) by key.
  • With index keys, inserting an item at the top gives every item the key of its neighbor. The props move to the new item, but the state and the DOM stay at the old position, so a typed note ends up next to another item.
  • If the items have no state and no uncontrolled inputs, an index only costs extra work: every shifted item gets new props and is updated instead of one new node being inserted.

key Outside of Lists​

A key can be put on any element. A different key means a different component for React: the old one is unmounted with its state and a new one is mounted. <ProfileForm key={userId} /> is the standard way to reset a form when the selected user changes, see Diffing Heuristics.

Example​

Type a note in the first row, then press the button: with index keys the note stays in the first row, next to the new task.

import { useState } from 'react';

let nextId = 3;

function Todo({ todo }) {
return (
<li>
{todo.text} <input placeholder="Note" />
</li>
);
}

export default function TodoList() {
const [todos, setTodos] = useState([
{ id: 1, text: 'Buy milk' },
{ id: 2, text: 'Walk the dog' },
]);

function addFirst() {
setTodos([{ id: nextId++, text: 'New task' }, ...todos]);
}

return (
<>
<button onClick={addFirst}>Add to the top</button>
<ul>
{todos.map((todo, index) => (
<Todo key={index} todo={todo} /> // the note stays in the first row
))}
</ul>
<ul>
{todos.map((todo) => (
<Todo key={todo.id} todo={todo} /> // the note moves with its task
))}
</ul>
</>
);
}

Follow-up Questions​

  • Why does React need keys at all? Without them it matches children by position: inserting an item at the top would update every item instead of inserting one node.
  • Where does the key go when map returns a component? On the component element, not on the root element inside the component.
  • Must a key be unique across the whole app? No, only among siblings.
  • When is an index fine? When the list is static: never reordered, filtered or inserted into.
  • Why not generate the key in render? A new key on every render remounts every item: state, focus and input values are lost, and the work grows.
  • What if the items have no ID? Generate one when the item is created (crypto.randomUUID() in the handler) or on the server, never in render. An index only if the list is static.
  • How to reset the state of a component? Change its key.

Common Mistakes​

  • The key on an element inside the component instead of the element returned from map.
  • key={Math.random()} to silence the warning.
  • An index as a key for a list that can be sorted, filtered or prepended to.
  • Reading props.key in the child.
  • "Keys are a performance optimization": they are about identity, see Optimizing React Components.

See Also​