Render lists efficiently with the key prop, understand reconciliation, and avoid common list rendering bugs.
const items = [
{ id: 1, name: "Alice" },
{ id: 2, name: "Bob" }
];
{items.map(item => (
<div key={item.id}>{item.name}</div>
))}// Without keys: input state follows the position, not the person
{people.map((person, index) => (
<div key={index}>
<input defaultValue={person.name} />
</div>
))}// Good: unique ID
{items.map(item => (
<div key={item.id}>{item.name}</div>
))}// Bad: index changes when items are reordered
{items.map((item, index) => (
<div key={index}>{item.name}</div>
))}import { v4 as uuidv4 } from "uuid";
const newItem = { id: uuidv4(), name: "Charlie" };// Problem: if items are sorted, indices change
const sorted = items.sort((a, b) => a.name.localeCompare(b.name));
sorted.map((item, i) => <Item key={i} />); // Bad!// Bad: new key generated on every render
items.map(item => (
<div key={Math.random()}>{item.name}</div>
))// Bad: object reference changes
{items.map(item => (
<div key={item}>{item.name}</div>
))}export default function UserList({ users }) {
return (
<ul>
{users.map(user => (
<li key={user.id}>{user.name}</li>
))}
</ul>
);
}if (users.length === 0) {
return <p>No users found</p>;
}
return (
<ul>
{users.map(user => (
<li key={user.id}>{user.name}</li>
))}
</ul>
);const active = users.filter(u => u.isActive);
const sorted = active.sort((a, b) => a.name.localeCompare(b.name));
return sorted.map(user => (
<UserItem key={user.id} user={user} />
));// With proper keys, React updates only changed items
{items.map(item => (
<Item key={item.id} data={item} />
))}// Bad: defines component inside map
items.map(item => {
const Component = createComponent(item);
return <Component key={item.id} />;
})
// Good: use a wrapper component
items.map(item => (
<ItemWrapper key={item.id} item={item} />
))const ListItem = React.memo(({ item }) => (
<div>{item.name}</div>
));
items.map(item => (
<ListItem key={item.id} item={item} />
))React uses keys to track which items changed, were added, or removed between renders. Without keys, React falls back to index-based diffing, which can cause incorrect component reuse and state bugs when the list changes.
No — keys generated at render time (like Math.random()) change every render, forcing React to unmount and remount every list item each time. This destroys component state and tanks performance.
An index-based key shifts when items are reordered or deleted, causing React to match the wrong component to the wrong data. A stable ID (like a database primary key) always points to the same item regardless of position.
No — keys only need to be unique among siblings in the same list. The same key value can appear in a completely different list without conflict.
Use a library like uuid or nanoid to assign a stable ID when the item is first created (e.g., on user input), and store that ID with the data. Never generate the key inline during render — generate it once and persist it.