Runnable lesson · press Try it on the examples to edit and run them here.
Array.prototype.map is the workhorse of React lists. It takes an array and returns a new array of the same length, built by calling a function on each item. If you need a refresher, read Array map.
map returns elements
function App() {
const numbers = [1, 2, 3];
const doubled = numbers.map((n) => n * 2);
return <p>{doubled.join(", ")}</p>;
}
In React, the callback returns JSX instead of numbers, so you get an array of elements, which React displays.
The arrow function and the parentheses
function App() {
const names = ["Ada", "Grace"];
return (
<ul>
{names.map((name) => (
<li key={name}>{name}</li>
))}
</ul>
);
}
Two syntaxes work, and they are a common cause of “nothing renders”:
// Parentheses: implicit return of the JSX
names.map((name) => (
<li key={name}>{name}</li>
))
// Curly braces: you MUST write return
names.map((name) => {
return <li key={name}>{name}</li>;
})
If you use curly braces and forget return, map produces an array of undefined values and the list is empty.
The index argument
map passes the position as a second argument:
function App() {
const names = ["Ada", "Grace", "Linus"];
return (
<ol style={{ listStyle: "none", padding: 0 }}>
{names.map((name, index) => (
<li key={name}>{index + 1}. {name}</li>
))}
</ol>
);
}
The index is good for display (numbering, striping rows). Do not use it as a key when the list can change; see Understanding React Keys.
Transform while mapping
Map is also how you turn data into a different shape before rendering:
function App() {
const people = [
{ id: 1, first: "Ada", last: "Lovelace" },
{ id: 2, first: "Grace", last: "Hopper" },
];
const fullNames = people.map((p) => `${p.first} ${p.last}`.toUpperCase());
return (
<ul>
{fullNames.map((n) => <li key={n}>{n}</li>)}
</ul>
);
}
Nested lists
Map inside map works. Give every level its own keys:
function App() {
const groups = [
{ id: "fe", title: "Frontend", skills: ["HTML", "CSS", "React"] },
{ id: "be", title: "Backend", skills: ["PHP", "MySQL"] },
];
return (
<div>
{groups.map((g) => (
<section key={g.id}>
<h3>{g.title}</h3>
<ul>
{g.skills.map((s) => <li key={s}>{s}</li>)}
</ul>
</section>
))}
</div>
);
}
Do the data work before the JSX
filter, sort and slice come before map. If the line gets long, put the prepared array in a variable:
function App() {
const products = [
{ id: 1, name: "Mouse", inStock: true },
{ id: 2, name: "Cable", inStock: false },
{ id: 3, name: "Hub", inStock: true },
];
const available = products.filter((p) => p.inStock);
return (
<ul>
{available.map((p) => <li key={p.id}>{p.name}</li>)}
</ul>
);
}
Common mistakes
- Forgetting
returnwhen using curly braces. - Calling
mapon something that is not an array (undefinedbefore data loads). Default to[]or check first. - Mutating in the callback (
items.sort()sorts the original). Copy first:[...items].sort(). - Missing keys, which React reports in the console.
Key points
mapturns an array of data into an array of elements.- With arrow functions: parentheses return implicitly; curly braces need
return. - Filter and sort first (on a copy), then map.