Technology · React
React Keys and Lists
Render lists efficiently with the key prop, understand reconciliation, and avoid common list rendering bugs.
TL;DR
- 01Always provide a key prop when rendering lists of items.
- 02Use stable, unique identifiers — not array indices.
- 03Keys help React identify which items changed for efficient updates.
Why Keys Matter
- Keys help React identify which items have changed, been added, or removed.
const items = [ { id: 1, name: "Alice" }, { id: 2, name: "Bob" } ]; {items.map(item => ( <div key={item.id}>{item.name}</div> ))} - Without keys, React assumes items are in the same position.
- This causes state to persist incorrectly between items.
// Without keys: input state follows the position, not the person {people.map((person, index) => ( <div key={index}> <input defaultValue={person.name} /> </div> ))} - Keys ensure component state stays with the correct item.
Choosing Good Keys
- Use stable, unique identifiers from your data.
// Good: unique ID {items.map(item => ( <div key={item.id}>{item.name}</div> ))} - Avoid array indices as keys, especially for dynamic lists.
// Bad: index changes when items are reordered {items.map((item, index) => ( <div key={index}>{item.name}</div> ))} - Use IDs from a database or UUID library for reliable keys.
import { v4 as uuidv4 } from "uuid"; const newItem = { id: uuidv4(), name: "Charlie" }; - Keys don't need to be globally unique, just unique within the list.
Common Mistakes
- Don't use array indices when the list can be reordered.
// 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! - Don't generate keys on the fly with random values.
// Bad: new key generated on every render items.map(item => ( <div key={Math.random()}>{item.name}</div> )) - Don't use complex objects as keys — use simple strings or numbers.
// Bad: object reference changes {items.map(item => ( <div key={item}>{item.name}</div> ))} - Always provide a key prop when rendering with map.
List Rendering Patterns
- Render a simple list with stable keys.
export default function UserList({ users }) { return ( <ul> {users.map(user => ( <li key={user.id}>{user.name}</li> ))} </ul> ); } - Handle empty lists gracefully.
if (users.length === 0) { return <p>No users found</p>; } return ( <ul> {users.map(user => ( <li key={user.id}>{user.name}</li> ))} </ul> ); - Filter and sort before rendering, not in the map.
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} /> ));
Performance Considerations
- Keys allow React to reuse DOM elements and preserve component state.
// With proper keys, React updates only changed items {items.map(item => ( <Item key={item.id} data={item} /> ))} - Avoid creating new components inside map — extract to separate component.
// 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} /> )) - Use React.memo on list items to avoid unnecessary re-renders.
const ListItem = React.memo(({ item }) => ( <div>{item.name}</div> )); items.map(item => ( <ListItem key={item.id} item={item} /> ))
Tip: Always use a unique identifier from your data as the key, preferably an ID from a database or UUID library.
Warning: Using array indices as keys causes bugs when lists are reordered, filtered, or items are added/removed dynamically.