List Rendering
Overview
You will rarely hardcode UI elements in React. Most of the time, you will receive an array of data from a backend API (like a list of users, products, or tweets) and need to dynamically generate a UI component for every item in that array.
In React, list rendering is accomplished using the standard JavaScript Array.prototype.map() function. You embed the .map() method directly inside your JSX using curly braces {}. For every piece of data in the array, you return a chunk of JSX, and React automatically unpacks that array of JSX elements and renders them to the screen.
This functional approach is far superior to standard for loops, as .map() is an expression that returns a new array, allowing it to be written cleanly and directly inline within the return statement.
Syntax
function ProductList() {
const products = [
{ id: 1, name: 'Laptop', price: 999 },
{ id: 2, name: 'Phone', price: 699 },
{ id: 3, name: 'Tablet', price: 399 }
];
return (
<div className="product-grid">
{/* We open curly braces to run JavaScript */}
{products.map((product) => (
// For every object, we return a block of JSX
// The 'key' prop is strictly required!
<div key={product.id} className="product-card">
<h3>{product.name}</h3>
<p>${product.price}</p>
</div>
))}
</div>
);
}Common Pitfalls
- Forgetting the 'return' in map: If you use curly braces for your arrow function
products.map(p => { <Card /> }), nothing will render because you forgot thereturnkeyword. Either use an implicit return with parentheses( <Card /> )or explicitly writereturn <Card />. - Missing the 'key' prop: Failing to provide a unique
keyprop to the outermost element returned by the.map()function will cause React to throw a glaring red warning in the console. (More on keys in the next topic).
Interview Questions
Because you can only put expressions (things that evaluate to a value) inside JSX curly braces {}. A for loop is a statement, not an expression, so it causes a syntax error inside JSX. .map() is an expression that iterates over an array and returns a brand new array of JSX elements, which React natively knows how to render.
Because .filter() and .map() both return arrays, you can perfectly chain them together inline. {users.filter(u => u.isActive).map(u => <UserCard key={u.id} user={u} />)}. This removes inactive users before they ever hit the map function.
Real-World Example
Rendering a Filtered Notification Feed: This demonstrates a highly common pattern: receiving an array from props, applying filtering logic based on user preferences, handling the empty state via an early return, and finally mapping the data into beautifully styled list items.
function NotificationFeed({ notifications, showOnlyUnread }) {
// We can process the array before returning JSX
const filteredNotes = showOnlyUnread
? notifications.filter(n => n.isRead === false)
: notifications;
if (filteredNotes.length === 0) {
return <p className="text-gray-500">You're all caught up!</p>;
}
return (
<ul className="feed-list">
{filteredNotes.map((note) => (
<li
key={note.id}
className={`p-4 ${note.isRead ? 'bg-white' : 'bg-blue-50 font-bold'}`}
>
<div className="flex justify-between">
<span>{note.message}</span>
<span className="text-sm text-gray-400">{note.time}</span>
</div>
</li>
))}
</ul>
);
}Check Your Knowledge
Test your understanding of List Rendering with these quick questions.