Lists & Keys
Rendering lists of data is one of the most common things you'll do in React. The pattern is simple: use JavaScript's .map() to transform an array of data into an array of JSX elements.
Basic List Rendering
basic.jsx
function FruitList() {
const fruits = ['Apple', 'Banana', 'Cherry', 'Date'];
return (
<ul>
{fruits.map((fruit, index) => (
<li key={index}>{fruit}</li>
))}
</ul>
);
}
// With objects from an API:
function UserList() {
const users = [
{ id: 1, name: 'Alice', role: 'admin' },
{ id: 2, name: 'Bob', role: 'student' },
{ id: 3, name: 'Carol', role: 'student' },
];
return (
<div>
{users.map(user => (
<div key={user.id}>
<strong>{user.name}</strong> — {user.role}
</div>
))}
</div>
);
}
Why Keys Matter
React needs a key prop on each list item to track which items changed, were added, or were removed. Without keys, React re-renders the entire list on every change — slow and buggy with form inputs.
keys.jsx
const todos = [
{ id: 'abc1', text: 'Buy groceries', done: false },
{ id: 'abc2', text: 'Write tests', done: true },
{ id: 'abc3', text: 'Ship feature', done: false },
];
// Good: using stable unique IDs
todos.map(todo => <li key={todo.id}>{todo.text}</li>);
// OK: index works only for static, non-reorderable lists
todos.map((todo, i) => <li key={i}>{todo.text}</li>);
// Bad: random keys force React to re-render everything
todos.map(todo => <li key={Math.random()}>{todo.text}</li>);
// Keys must be unique AMONG SIBLINGS, not globally
// Two different lists can have items with the same key
Never use the array index as a key if the list can be reordered or filtered. Use a unique ID from your data instead.
Rendering Component Lists
You'll usually render components instead of raw elements:
components.jsx
function ProductCard({ product }) {
return (
<div className="card">
<h3>{product.name}</h3>
<p>${product.price.toFixed(2)}</p>
<span className={`badge ${product.inStock ? 'green' : 'red'}`}>
{product.inStock ? 'In Stock' : 'Out of Stock'}
</span>
</div>
);
}
function ProductGrid({ products }) {
if (products.length === 0) {
return <p>No products found.</p>;
}
return (
<div className="grid">
{products.map(product => (
<ProductCard key={product.id} product={product} />
))}
</div>
);
}
Conditional List Items
filter.jsx
import { useState } from 'react';
function FilteredList() {
const [filter, setFilter] = useState('all');
const tasks = [
{ id: 1, text: 'Design', status: 'done' },
{ id: 2, text: 'Build', status: 'active' },
{ id: 3, text: 'Test', status: 'active' },
{ id: 4, text: 'Deploy', status: 'pending' },
];
const visible = tasks.filter(t =>
filter === 'all' ? true : t.status === filter
);
return (
<div>
<div>
{['all', 'active', 'done', 'pending'].map(f => (
<button key={f} onClick={() => setFilter(f)}
style={{ fontWeight: filter === f ? 'bold' : 'normal' }}>
{f}
</button>
))}
</div>
<ul>
{visible.map(task => (
<li key={task.id}>{task.text} ({task.status})</li>
))}
</ul>
<p>{visible.length} tasks shown</p>
</div>
);
}