Key Property in React
The key prop is a special attribute that helps React identify which items have changed, been added, or been removed in lists.
Table of Contents
What is the Key Property?
The key prop is a special string attribute that React uses to identify elements in lists. It helps React track which items have changed, been added, or been removed.
Basic Usage:
function TodoList({ todos }) {
return (
<ul>
{todos.map(todo => (
<li key={todo.id}>{todo.text}</li>
))}
</ul>
);
}
Key Characteristics:
- Unique: Each key should be unique among siblings
- Stable: Should not change between renders
- Predictable: Should be based on item identity, not position
Why Keys are Important
1. Efficient Reconciliation:
// Without keys - React doesn't know which items changed
function BadList({ items }) {
return (
<ul>
{items.map(item => (
<li>{item.text}</li> // No key
))}
</ul>
);
}
// With keys - React can efficiently track changes
function GoodList({ items }) {
return (
<ul>
{items.map(item => (
<li key={item.id}>{item.text}</li> // Has key
))}
</ul>
);
}
2. State Preservation:
function UserList({ users }) {
return (
<div>
{users.map(user => (
<UserCard
key={user.id} // Preserves component state
user={user}
/>
))}
</div>
);
}
function UserCard({ user }) {
const [isExpanded, setIsExpanded] = useState(false);
return (
<div>
<h3>{user.name}</h3>
{isExpanded && <p>{user.email}</p>}
<button onClick={() => setIsExpanded(!isExpanded)}>
{isExpanded ? 'Hide' : 'Show'} Email
</button>
</div>
);
}
3. Performance Optimization:
// React can efficiently update only changed items
const todos = [
{ id: 1, text: 'Learn React' },
{ id: 2, text: 'Build app' },
{ id: 3, text: 'Deploy' }
];
// If we add a new todo at the beginning
const newTodos = [
{ id: 4, text: 'Plan project' }, // New item
{ id: 1, text: 'Learn React' }, // Existing item
{ id: 2, text: 'Build app' }, // Existing item
{ id: 3, text: 'Deploy' } // Existing item
];
// React knows to only create the new element, not re-render existing ones
Best Practices
1. Use Stable IDs:
// Good: Use unique, stable IDs
function TodoList({ todos }) {
return (
<ul>
{todos.map(todo => (
<li key={todo.id}>{todo.text}</li>
))}
</ul>
);
}
// Good: Use unique identifiers
function UserList({ users }) {
return (
<ul>
{users.map(user => (
<li key={user.email}>{user.name}</li>
))}
</ul>
);
}
2. Avoid Array Index:
// Bad: Using array index as key
function BadList({ items }) {
return (
<ul>
{items.map((item, index) => (
<li key={index}>{item.text}</li> // Unstable key
))}
</ul>
);
}
// Good: Use stable identifiers
function GoodList({ items }) {
return (
<ul>
{items.map(item => (
<li key={item.id}>{item.text}</li> // Stable key
))}
</ul>
);
}
3. Generate Keys for Dynamic Lists:
// Good: Generate unique keys
function DynamicList({ items }) {
return (
<ul>
{items.map((item, index) => (
<li key={`${item.type}-${item.id}-${index}`}>
{item.text}
</li>
))}
</ul>
);
}
// Good: Use timestamp + random for truly unique keys
function UniqueList({ items }) {
return (
<ul>
{items.map(item => (
<li key={`${Date.now()}-${Math.random()}`}>
{item.text}
</li>
))}
</ul>
);
}
4. Keys in Nested Lists:
function NestedList({ categories }) {
return (
<div>
{categories.map(category => (
<div key={category.id}>
<h2>{category.name}</h2>
<ul>
{category.items.map(item => (
<li key={`${category.id}-${item.id}`}>
{item.name}
</li>
))}
</ul>
</div>
))}
</div>
);
}
Common Mistakes
1. Using Index as Key:
// Problem: Index changes when items are reordered
const items = ['Apple', 'Banana', 'Cherry'];
// Initial render
items.map((item, index) => <li key={index}>{item}</li>);
// Renders: key="0" -> Apple, key="1" -> Banana, key="2" -> Cherry
// After removing first item
items = ['Banana', 'Cherry'];
items.map((item, index) => <li key={index}>{item}</li>);
// Renders: key="0" -> Banana, key="1" -> Cherry
// React thinks Banana changed from "Apple" to "Banana"
2. Using Random Values:
// Problem: New key on every render
function BadList({ items }) {
return (
<ul>
{items.map(item => (
<li key={Math.random()}>{item.text}</li> // New key every time
))}
</ul>
);
}
// Solution: Use stable identifiers
function GoodList({ items }) {
return (
<ul>
{items.map(item => (
<li key={item.id}>{item.text}</li> // Stable key
))}
</ul>
);
}
3. Missing Keys:
// Problem: React warning and inefficient updates
function BadList({ items }) {
return (
<ul>
{items.map(item => (
<li>{item.text}</li> // No key
))}
</ul>
);
}
// Solution: Always provide keys
function GoodList({ items }) {
return (
<ul>
{items.map(item => (
<li key={item.id}>{item.text}</li> // Has key
))}
</ul>
);
}
4. Non-Unique Keys:
// Problem: Duplicate keys
function BadList({ items }) {
return (
<ul>
{items.map(item => (
<li key="item">{item.text}</li> // Same key for all items
))}
</ul>
);
}
// Solution: Unique keys
function GoodList({ items }) {
return (
<ul>
{items.map(item => (
<li key={item.id}>{item.text}</li> // Unique key
))}
</ul>
);
}
Common Interview Questions
Q: What is the key prop in React?
- A special attribute that helps React identify which items have changed, been added, or been removed in lists.
Q: Why are keys important in React?
- They help React efficiently track and update list items, preserve component state, and optimize performance.
Q: What happens if you don’t provide a key?
- React will use array index as key, which can cause issues with state preservation and inefficient updates.
Q: Can you use array index as a key?
- It’s not recommended because it can cause issues when items are reordered, added, or removed from the list.
Q: What makes a good key?
- Unique, stable, and predictable identifiers that don’t change between renders.
Q: How do keys help with performance?
- They allow React to efficiently update only the items that have changed instead of re-rendering the entire list.
Q: What happens if you use duplicate keys?
- React will warn about duplicate keys and may not work correctly with state preservation.
Summary
- Keys help React identify and track list items efficiently
- Unique and stable keys are essential for proper reconciliation
- Avoid array index as keys when items can be reordered
- Use stable identifiers like database IDs or unique properties
- Keys preserve component state when items are reordered
- Missing keys cause React warnings and inefficient updates
- Duplicate keys can cause unexpected behavior
- Keys are crucial for performance optimization in dynamic lists
Interview angle
- “What does
keydo?” - gives an element a stable identity across renders so reconciliation can match, move and preserve state instead of destroying and rebuilding. It is a hint to React, never readable as a prop. - “Why are index keys dangerous?” - they are positional. Insert at the front, delete, or reorder, and React matches item 0 to a different item: DOM state such as input text, focus and scroll position sticks to the wrong row. Index keys are only safe for a list that is static and never reordered or filtered.
- “How do you deliberately reset state?” - change the key. Giving a component
key={userId}remounts it when the user changes, which is the cleanest way to clear internal state without an effect. - “Must keys be globally unique?” - only among siblings.