Rendering collections in React refers to taking a collection (usually an array) and transforming it into a collection of JSX elements to be rendered in the interface.
For example, a list of products for an e-commerce site, comments on a website, or users in an admin panel.
In this article, we will see how React converts these data Arrays into Arrays of visual components.
The .map() Method
If you come from imperative programming (regular programming), your instinct is probably to use a for loop or forEach to iterate over the data and render things.
But remember that in JSX we can only use expressions (things that return a value). And a for loop… doesn’t return anything 😉.
That’s why, in React, the standard method for rendering lists is .map().
The .map() method is perfect because it transforms one array into another array of the same size. We take an array of data (objects, strings) and transform it into an array of JSX elements.
const fruits = ['Apple', 'Banana', 'Cherry'];
function FruitList() {
// We transform strings -> <li>
const listItems = fruits.map((fruit) => {
return <li>{fruit}</li>;
});
return (
<ul>
{listItems}
</ul>
);
}
Generally, we do this directly inside the JSX (inline) to save code:
function FruitList() {
const fruits = ['Apple', 'Banana', 'Cherry'];
return (
<ul>
{fruits.map((fruit) => (
<li>{fruit}</li>
))}
</ul>
);
}
React is smart enough to receive an array of JSX elements and render them one after the other.
Rendering Components
Of course, we are not limited to simple HTML tags like <li>. We can use it to render entire components.
Imagine we have an array of objects:
const users = [
{ id: 1, name: 'Luis', role: 'Admin' },
{ id: 2, name: 'María', role: 'User' },
{ id: 3, name: 'Carlos', role: 'Editor' }
];
function UserList() {
return (
<div className="grid">
{users.map((user) => (
// We pass the whole object or individual props
<UserCard
name={user.name}
role={user.role}
/>
))}
</div>
);
}
So far everything seems correct. The code works and we see the list. But if we open the browser console (F12), we will see a warning in blaring red.
Warning: Each child in a list should have a unique “key” prop.
You’ve just encountered one of the most common and famous warning messages in React. Why does it happen? Let’s see right now 👇.
The Importance of the key
The previous message complains that you haven’t defined the key prop. This is a special attribute we must include when creating lists of elements.
// Correct way
<UserCard key={user.id} name={user.name} ... />
Each element in a list rendered with .map() must have a special property called key. This key allows React to identify each item uniquely when updating or reordering elements.
Rules for Using Keys
- They must be unique: Each key must be unique within the list. Do not use the array index as a key unless you have no other option.
- They must be stable: Keys should not change between renders. For example, do not use a random value as a key.
What to Use as a Key?
Unique IDs (the best option)
Ideally, use data that comes from your database: numeric IDs, UUIDs, Slugs, ID numbers, etc. Something that uniquely identifies that piece of data in the universe.
{products.map(product => (
<Product key={product.id} data={product} />
))}
Array Indices (the bad option)
It’s very tempting to use the second argument of .map() (the index) as a key.
// AVOID THIS IF POSSIBLE!
{items.map((item, index) => (
<li key={index}>{item}</li>
))}
Using the index silences the console warning, but does not solve the problem.
If the list is static (never changes, never reorders, never gets filtered), using the index is acceptable.
But if the list can change order, delete elements, or insert them, using the index will cause bugs.
Never use IDs with Math.random()
Never, under any circumstances, generate keys on the fly with key={Math.random()}.
This will cause the keys to change on every render, forcing React to destroy and create all the list elements constantly.
Performance will plummet and you will lose focus on inputs (you’ll get fired, and possibly your poppies will wither 🌻).
Technical Details to Keep in Mind
- Keys must be unique among siblings: They don’t need to be unique across the entire app (if they are, even better), only within their parent list.
- The Key is defined in the
.map(): If you extract the element into a component, the key goes in the component call, not inside the component’s HTML.
// ❌ WRONG
function List() {
return items.map(item => <Item item={item} />);
}
function Item({ item }) {
return <li key={item.id}>{item.name}</li>; // The key here is useless
}
// ✔️ CORRECT
function List() {
// The key goes on the outermost element returned by the map
return items.map(item => <Item key={item.id} item={item} />);
}
- The Key is not a Prop: If you try to read
props.keyinside the child component, you’ll see it’sundefined. React “eats” the key for its internal use and doesn’t pass it down. If you need the ID inside the component, pass it in another explicit prop (e.g.,id={user.id}).
