Margherita
8.50 €
Nikita Goluban
Full-Stack Developer Logistics & Marketing Mechanical & Construction Skills Woodwork & Metalwork Polyglot
React.js + Next.js · Module 2. React Basics · Lesson 8
React applications often display collections of data. Pizza Palace needs collections for:
Instead of writing every card manually, we store the data in a JavaScript array and transform it into JSX with .map().
.map() generates elements and components.key values.REACT · 01
A collection is a group of values. In JavaScript, collections are commonly stored in arrays.
const quantities = [1, 2, 3];
const pizzaNames = [
"Margherita",
"Pepperoni",
"Vegetarian"
];
const pizzas = [
{ id: 1, name: "Margherita", price: 8.5 },
{ id: 2, name: "Pepperoni", price: 10.5 },
{ id: 3, name: "Vegetarian", price: 9.5 }
];
Each object describes one pizza. React can transform these objects into menu cards.
REACT · 02
We could write every pizza manually:
function App() {
return (
<div>
<p>Margherita</p>
<p>Pepperoni</p>
<p>Vegetarian</p>
</div>
);
}
export default App;
This works for three items but becomes difficult for a large or changing menu. With .map(), the array becomes the source of truth and React generates the JSX automatically.
REACT · 03
The .map() method creates a new array by applying a function to every item in an existing array.
const prices = [8, 10, 12];
const pricesWithDelivery = prices.map(function (price) {
return price + 2;
});
console.log(pricesWithDelivery);
[10, 12, 14]
The callback runs once for each price and returns a new value. .map() does not modify the original prices array.
Use .map() when you need a new value for every item. Later, JSX elements will be those new values.
REACT · 04
Place the .map() expression inside JSX curly braces.
const quantities = [1, 2, 3];
function App() {
return (
<div>
{quantities.map(function (quantity) {
return <p key={quantity}>Quantity: {quantity}</p>;
})}
</div>
);
}
export default App;
Step by step:
quantities stores the data..map() visits every number.<p> for each number.REACT · 05
An array of unique pizza names can become a list.
const pizzaNames = [
"Margherita",
"Pepperoni",
"Vegetarian"
];
function App() {
return (
<main>
<h1>Pizza Menu</h1>
<ul>
{pizzaNames.map(function (pizzaName) {
return <li key={pizzaName}>{pizzaName}</li>;
})}
</ul>
</main>
);
}
export default App;
Using a name as a key is safe only when every name is unique and stable. Real menu data should normally have an ID.
REACT · 06
Real menu items need more than a name.
const pizzas = [
{ id: 1, name: "Margherita", price: 8.5 },
{ id: 2, name: "Pepperoni", price: 10.5 },
{ id: 3, name: "Vegetarian", price: 9.5 }
];
function App() {
return (
<main>
<h1>Pizza Menu</h1>
{pizzas.map(function (pizza) {
return (
<article key={pizza.id}>
<h2>{pizza.name}</h2>
<p>Price: {pizza.price} €</p>
</article>
);
})}
</main>
);
}
export default App;
Inside the callback, pizza represents one object. We read pizza.id, pizza.name, and pizza.price with dot notation.
REACT · 07
React uses the special key attribute to identify siblings in a rendered collection.
<article key={pizza.id}>
<h2>{pizza.name}</h2>
</article>
Keys help React match old items to new items when a pizza is added, removed, or moved.
A good key is:
The usual choice is:
key={pizza.id}
key is not passed to a child component as a normal prop. If PizzaCard also needs the ID, pass it separately:
<PizzaCard
key={pizza.id}
id={pizza.id}
name={pizza.name}
/>
REACT · 08
Array indexes describe positions, not item identities.
pizzas.map(function (pizza, index) {
return <PizzaCard key={index} name={pizza.name} />;
})
Imagine the original cart:
Index 0 → Margherita
Index 1 → Pepperoni
Index 2 → Vegetarian
After removing Margherita:
Index 0 → Pepperoni
Index 1 → Vegetarian
The indexes now refer to different pizzas. React may associate existing component state with the wrong item.
Prefer key={pizza.id} when items can be inserted, removed, filtered, or reordered.
An index can be acceptable for a simple static list when items never change and no stable ID exists.
REACT · 09
Do not generate a new key during every render.
Incorrect:
<PizzaCard key={Math.random()} name={pizza.name} />
The value changes each time, so React may treat the card as a completely new component. That can cause unnecessary remounting and loss of local state.
Correct:
<PizzaCard key={pizza.id} name={pizza.name} />
Also avoid generating keys from the current time during rendering.
REACT · 10
Define the structure of one pizza with an interface:
interface Pizza {
id: number;
name: string;
price: number;
isVegetarian: boolean;
}
Then type the array:
const pizzas: Pizza[] = [
{ id: 1, name: "Margherita", price: 8.5, isVegetarian: true },
{ id: 2, name: "Pepperoni", price: 10.5, isVegetarian: false }
];
Pizza describes one object. Pizza[] means an array containing Pizza objects.
Incorrect:
const pizzas: Pizza[] = [
{ id: 1, name: "Margherita", price: "8.50", isVegetarian: true }
];
TypeScript reports an error because price must be a number, not a string.
REACT · 11
Combine a TypeScript interface with .map().
interface Pizza {
id: number;
name: string;
price: number;
}
const pizzas: Pizza[] = [
{ id: 1, name: "Margherita", price: 8.5 },
{ id: 2, name: "Pepperoni", price: 10.5 },
{ id: 3, name: "Vegetarian", price: 9.5 }
];
export default function App() {
return (
<main>
<h1>Pizza Menu</h1>
{pizzas.map(function (pizza) {
return (
<article key={pizza.id}>
<h2>{pizza.name}</h2>
<p>Price: {pizza.price} €</p>
</article>
);
})}
</main>
);
}
TypeScript knows that each pizza contains id, name, and price.
REACT · 12
In a real application, create a reusable component for each list item.
interface PizzaCardProps {
name: string;
price: number;
}
function PizzaCard(props: PizzaCardProps) {
return (
<article>
<h2>{props.name}</h2>
<p>Price: {props.price} €</p>
</article>
);
}
export default PizzaCard;
import PizzaCard from "./components/PizzaCard";
interface Pizza {
id: number;
name: string;
price: number;
}
const pizzas: Pizza[] = [
{ id: 1, name: "Margherita", price: 8.5 },
{ id: 2, name: "Pepperoni", price: 10.5 },
{ id: 3, name: "Vegetarian", price: 9.5 }
];
export default function App() {
return (
<main>
<h1>Pizza Menu</h1>
{pizzas.map(function (pizza) {
return (
<PizzaCard
key={pizza.id}
name={pizza.name}
price={pizza.price}
/>
);
})}
</main>
);
}
App maps data into three reusable PizzaCard components..map() handles repetition, props provide each pizza's data, and PizzaCard owns the presentation.
REACT · 13
A parent can store the menu array and pass it to PizzaMenu.
import PizzaCard from "./PizzaCard";
interface Pizza {
id: number;
name: string;
price: number;
}
interface PizzaMenuProps {
pizzas: Pizza[];
}
function PizzaMenu(props: PizzaMenuProps) {
return (
<section>
{props.pizzas.map(function (pizza) {
return (
<PizzaCard
key={pizza.id}
name={pizza.name}
price={pizza.price}
/>
);
})}
</section>
);
}
export default PizzaMenu;
import PizzaMenu from "./components/PizzaMenu";
const pizzas = [
{ id: 1, name: "Margherita", price: 8.5 },
{ id: 2, name: "Pepperoni", price: 10.5 }
];
export default function App() {
return (
<main>
<h1>Pizza Palace</h1>
<PizzaMenu pizzas={pizzas} />
</main>
);
}
App provides the array; PizzaMenu renders it.This parent-to-child collection pattern is common in React applications.
REACT · 14
An empty array produces no list items. A helpful message gives customers a clearer result.
interface Pizza {
id: number;
name: string;
}
const pizzas: Pizza[] = [];
export default function App() {
return (
<main>
<h1>Pizza Menu</h1>
{pizzas.length === 0 ? (
<p>No pizzas are currently available.</p>
) : (
<ul>
{pizzas.map(function (pizza) {
return <li key={pizza.id}>{pizza.name}</li>;
})}
</ul>
)}
</main>
);
}
This combines the conditional rendering from Lesson 7 with .map().
REACT · 16
Incorrect:
pizzas.map(function (pizza) {
<p key={pizza.id}>{pizza.name}</p>;
})
Correct:
pizzas.map(function (pizza) {
return <p key={pizza.id}>{pizza.name}</p>;
})
Incorrect:
pizzas.map(function (pizza) {
return <PizzaCard name={pizza.name} />;
})
Correct:
pizzas.map(function (pizza) {
return <PizzaCard key={pizza.id} name={pizza.name} />;
})
The key belongs on the element returned directly by .map().
return <PizzaCard key={pizza.id} name={pizza.name} />;
If the child needs the ID, pass both values:
<PizzaCard key={pizza.id} id={pizza.id} name={pizza.name} />
.forEach() returns undefined; .map() returns the new array of JSX elements React needs.
REACT · 17
Create an array with three pizza names and render them as <li> elements with .map().
Create a Pizza interface with id, name, and price. Render three pizza objects as cards.
Move the card markup into PizzaCard.tsx and pass the pizza data through props.
Display No pizzas are currently available when the array is empty.
Give every pizza a stable ID. Remove one item and confirm that the remaining IDs do not change.
Create a typed cart array containing id, pizzaName, quantity, and unitPrice. Render the line total for every item.
REACT · 18
.map() creates a new value for every array item.key for every sibling generated by .map().Math.random() or the current time during rendering.key is special and is not passed as a normal prop.Pizza[] describes the array.REACT · 19
Next lesson: Rendering a React application in the DOM with index.html, main.tsx, createRoot(), and the Pizza Palace App component.