Runnable lesson · press Try it on the examples to edit and run them here.
Most real screens show lists: products, messages, tasks, search results. In React you keep the list as data (an array) and turn it into elements.
The idea
You do not write one <li> per item by hand. You write one description of an item and let JavaScript repeat it for every element in the array.
function App() {
const tasks = ["Learn React", "Build a project", "Deploy it"];
return (
<ul>
{tasks.map((task) => (
<li key={task}>{task}</li>
))}
</ul>
);
}
tasks.map(...) returns a new array of elements, and React renders every element of that array in order. Adding or removing items from tasks changes the screen automatically.
Lists of objects
Real data is usually objects with an id:
function App() {
const products = [
{ id: 1, name: "Keyboard", price: 49 },
{ id: 2, name: "Mouse", price: 25 },
{ id: 3, name: "Monitor", price: 189 },
];
return (
<table>
<thead>
<tr><th>Product</th><th>Price</th></tr>
</thead>
<tbody>
{products.map((product) => (
<tr key={product.id}>
<td>{product.name}</td>
<td>${product.price}</td>
</tr>
))}
</tbody>
</table>
);
}
A component per item
When an item gets more complex, make it a component and pass the data as props:
function ProductRow({ name, price }) {
return <li>{name} - ${price}</li>;
}
function App() {
const products = [
{ id: 1, name: "Keyboard", price: 49 },
{ id: 2, name: "Mouse", price: 25 },
];
return (
<ul>
{products.map((p) => (
<ProductRow key={p.id} name={p.name} price={p.price} />
))}
</ul>
);
}
The key goes on the element returned by map, which here is <ProductRow />, not on something inside ProductRow.
Lists change over time
Because the list is data, you change it like any other state, by creating a new array. Here items can be added:
function App() {
const [tasks, setTasks] = React.useState([{ id: 1, text: "Learn React" }]);
const [text, setText] = React.useState("");
function addTask() {
if (!text.trim()) return;
setTasks([...tasks, { id: Date.now(), text }]);
setText("");
}
return (
<div>
<input aria-label="New task" value={text} onChange={(e) => setText(e.target.value)} />
<button onClick={addTask}>Add task</button>
<p>Tasks: {tasks.length}</p>
<ul>
{tasks.map((t) => <li key={t.id}>{t.text}</li>)}
</ul>
</div>
);
}
[...tasks, newTask] builds a new array (never tasks.push(...); see Updating Arrays in State).
Things to remember
- Always give each rendered item a key: Understanding React Keys.
- Handle the empty list: Empty States.
- Do any filtering or sorting before you map: Filtering and Sorting Lists.
Key points
- Keep lists as arrays of data and render them with
map. - Each element returned from
mapneeds a stablekey. - Change lists by creating new arrays, and React updates the screen.