react:列表渲染 (List Rendering)

4 阅读3分钟

这是 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 (列表) 结合起来。

这是一个非常经典的交互:点击某一项,把它从列表中删掉。

逻辑提示:

  1. 数据必须存在 useState 里(因为删除会导致界面变化)。
  2. 删除逻辑:使用 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;