这是 React 开发中最常用的功能。只要你做过网站,就一定离不开列表(新闻列表、商品列表、好友列表、评论列表……)。
在 React 中,我们不使用 for 循环来渲染列表,而是使用数组的一个魔法方法: .map() 。
1. 核心概念:map 的映射魔法
想象你手里有一张**“数据清单” (数组),你想把它变成一堆“HTML 卡片”**。
map 的作用就是:遍历清单里的每一项,按照你给的模板,生成一个新的 UI 数组。
语法公式:
数据数组.map( (每一项) => <HTML模板 /> )
2. 实战演示:渲染商品列表
请清空你的 App.jsx,换成下面的代码。我们要渲染三个手机商品。
JavaScript
function App() {
// 1. 准备数据 (通常这些数据来自后端 API,现在我们先写死)
const products = [
{ id: 1, name: "iPhone 15", price: 5999 },
{ id: 2, name: "小米 14", price: 3999 },
{ id: 3, name: "华为 Mate 60", price: 6999 }
];
return (
<div>
<h1>手机大卖场</h1>
{/* 2. 开始列表渲染 */}
<ul>
{/* 注意:在 JSX 里写 JS 逻辑,必须套在 {} 里 */}
{products.map((product) => (
<li key={product.id} style={{ marginBottom: '10px', padding: '10px', border: '1px solid #ddd' }}>
<h3>{product.name}</h3>
<p>价格:¥{product.price}</p>
</li>
))}
</ul>
</div>
);
}
export default App;
3. ⚠️ 极其重要的知识点:key
仔细看上面代码里 <li key={product.id}> 这一行。
如果你不写 key,代码也能跑,但控制台会报一个鲜红的警告:
Warning: Each child in a list should have a unique "key" prop.
为什么要写 key?
React 需要通过这个“身份证号”来区分每一个组件。
- 如果列表顺序变了(比如删除了第二项),React 有了 key 就能精准知道“哦,是 ID 为 2 的那个没了”,而不是把整个列表全部推倒重绘。
- 规则: key 必须在该列表中是唯一的(通常用数据库里的 ID,尽量别用数组索引 index)。
4. 进阶实战:结合 useState 做一个“待办事项删除”功能
现在我们把 State (状态) 和 List (列表) 结合起来。
这是一个非常经典的交互:点击某一项,把它从列表中删掉。
逻辑提示:
- 数据必须存在
useState里(因为删除会导致界面变化)。- 删除逻辑:使用
filter方法创建一个新数组,把要删的那个过滤掉。
请仔细阅读并运行这段代码:
JavaScript
import { useState } from 'react';
function App() {
// 1. 把数据放进 State 里,这样数据变了界面才会变
const [tasks, setTasks] = useState([
{ id: 1, text: "学习 React" },
{ id: 2, text: "写代码" },
{ id: 3, text: "去跑步" }
]);
// 删除功能的函数
function handleDelete(idToDelete) {
console.log("我要删除 ID 为 " + idToDelete + " 的任务");
// filter 是过滤的意思:只保留 ID 不等于 idToDelete 的那些项
// 也就是把等于 idToDelete 的那一项踢出去
const newTasks = tasks.filter(task => task.id !== idToDelete);
// 更新状态
setTasks(newTasks);
}
return (
<div>
<h1>待办事项 (点击删除)</h1>
<ul>
{tasks.map(task => (
<li key={task.id} style={{ margin: '10px 0' }}>
<span>{task.text}</span>
{/* 这里的 onClick 写法稍微有点特殊,用了一个箭头函数包裹 */}
{/* 因为我们需要把 task.id 传进去 */}
<button
onClick={() => handleDelete(task.id)}
style={{ marginLeft: '10px', color: 'red' }}
>
删除
</button>
</li>
))}
</ul>
{/* 如果数组空了,显示一句话 */}
{tasks.length === 0 && <p>恭喜!所有任务都完成了 🎉</p>}
</div>
);
}
export default App;