Using the index of an array as the key when rendering a list in React might seem convenient, but it can lead to performance issues and unexpected bugs. The key prop is crucial for helping React identify which items have changed, been added, or removed.
In this guide, we'll explore why you should avoid using indices as keys and what the best practices are for proper list rendering.
key PropBefore diving into the problems, let's understand why React needs keys. When a component's state or props change, React needs to decide how to update the DOM efficiently. It compares the new virtual DOM tree with the old one (a process called reconciliation).
Keys provide a stable identity for elements across re-renders. Without unique keys, React can't tell if an item was moved, updated, or replaced.
The key prop is used by React to identify elements in the DOM. If you use the index of an array as the key, React can get confused when the array is modified. Since indices are tied to the position rather than the content, adding or removing items changes the identity of every subsequent element.
Arrays in JavaScript are zero-indexed (0, 1, 2, 3...). When you add a new item at the beginning of the array, all subsequent items will have their indices shifted.
[0: A, 1: B, 2: C][0: New, 1: A, 2: B, 3: C]React will interpret this as if every single item has changed and will re-render the entire list, leading to unnecessary performance costs, especially in large applications.
This is perhaps the most dangerous issue. If you use indices as keys and the order of items changes, the local state associated with each item (like input values or animations) may get mixed up.
Warning: If your list items contain stateful components (like inputs, checkboxes, or focus states), using indices as keys will almost certainly cause bugs.
import React, { useState } from "react";
const ItemListWithIndexKey = () => {
const [items, setItems] = useState(["Item 1", "Item 2", "Item 3"]);
const addItem = () => {
// Adding to the beginning of the list
const newItem = `Item ${items.length + 1}`;
setItems([newItem, ...items]);
};
return (
<div className="p-4">
<button
onClick={addItem}
className="px-4 py-2 bg-red-500 text-white rounded-md mb-4"
>
Add Item to Top
</button>
<ul className="space-y-2">
{items.map((item, index) => (
<li key={index} className="p-2 border rounded">
{item} <input placeholder="Type something..." className="ml-2 border p-1" />
</li>
))}
</ul>
</div>
);
};In the example above, if you type something into the first input and then click "Add Item", you'll notice that your text stays in the first input, even though the "Item 1" label moved down. This is because React thinks the first element (key 0) is still the same element.
Instead of using indices, use unique identifiers (such as IDs from your database). This way, React can properly track and manage the items, leading to better performance and fewer bugs.
import React, { useState } from "react";
const ItemList = () => {
const [items, setItems] = useState([
{ id: 'id-1', name: "Item 1" },
{ id: 'id-2', name: "Item 2" },
{ id: 'id-3', name: "Item 3" },
]);
const addItem = () => {
const newItem = {
id: crypto.randomUUID(), // Modern way to generate unique ID
name: `Item ${items.length + 1}`,
};
setItems([newItem, ...items]);
};
return (
<div className="p-4">
<button
onClick={addItem}
className="px-4 py-2 bg-green-500 text-white rounded-md mb-4"
>
Add Item Securely
</button>
<ul className="space-y-2">
{items.map((item) => (
<li key={item.id} className="p-2 border rounded">
{item.name} <input placeholder="Type something..." className="ml-2 border p-1" />
</li>
))}
</ul>
</div>
);
};crypto.randomUUID() or nanoid, but NOT during the render phase.email or slug? Use that as the key.By following these rules, you'll ensure your React applications are performant, bug-free, and maintainable.
Math.random() as it changes on every renderUsing index as a key is acceptable only when ALL of these conditions are true:
Check out the live example on CodeSandbox to see the difference in behavior: Live Demo
By using unique identifiers as keys, you help React efficiently update the DOM and avoid common pitfalls associated with using indices. This simple change can significantly improve your application's:
Remember: Keys are not just for React's warnings—they're essential for correct and performant list rendering!
More articles you might find interesting
Have you ever tried to log or send state immediately after calling its set function, only to find the old value instead? This is one of the most common "aha!" moments for React developers.
Learn how to implement recursion in React components to manage nested radio button groups using JavaScript's Map object for efficient state management.
Learn how to streamline your API data handling by efficiently removing null, undefined, and empty values from JavaScript objects using Lodash and recursion.