【React】通过实际示例详解评论列表渲染和删除

news2024/11/15 21:46:27

文章目录

    • 一、引言
    • 二、初始状态与状态更新
      • 1. 使用`useState`钩子管理状态
      • 2. 评论列表的初始数据
    • 三、列表渲染的实现
      • 1. `list.map(item => { ... })`
      • 2. `return` 语句
      • 3. JSX 语法
      • 4. 为什么这样设计
      • 5. 完整解读
    • 四、列表项的唯一标识
      • 1. `key` 的作用
      • 2. `key` 的用法
      • 3. 可以没有 `key` 吗?
      • 4. 示例代码中的 `key`
    • 五、处理评论删除
      • 1. 删除评论的实现
      • 2. 条件渲染删除按钮
    • 六、完整代码示例

在React开发中,列表渲染是一个非常常见且重要的功能。本文将通过一个实际的评论列表渲染例子,详细介绍如何使用React的useState钩子和数组方法动态渲染和更新列表。本文内容从基础到进阶,涵盖了核心概念和实现方法,帮助开发者掌握React中的列表渲染技术。

一、引言

在现代Web开发中,动态数据的渲染和更新是常见需求。React作为一个强大的前端框架,通过其灵活的状态管理和组件化设计,使得处理这些需求变得更加简单和高效。本文将通过一个完整的App组件代码,详细解析其中的评论列表渲染和更新的实现。

二、初始状态与状态更新

1. 使用useState钩子管理状态

在React函数组件中,useState钩子用于声明状态变量并提供更新函数。以下代码声明了一个初始评论列表的状态变量list,并使用setList函数来更新它:

const [list, setList] = useState(defaultList);

2. 评论列表的初始数据

const defaultList = [
  {
    rpid: 3,
    user: {
      uid: '13258165',
      avatar: '',
      uname: '周杰伦',
    },
    content: '哎哟,不错哦',
    ctime: '10-18 08:15',
    like: 88,
  },
  // 其他评论数据...
];

三、列表渲染的实现

在React中,使用map方法可以方便地将数组数据转换为React元素。以下代码展示了如何遍历list数组并生成评论列表:

<div className="reply-list">
  {list.map(item => {
    return (
      <div key={item.rpid} className="reply-item">
        {/* 头像 */}
        <div className="root-reply-avatar">
          <div className="bili-avatar">
            <img
              className="bili-avatar-img"
              src={item.user.avatar}
              alt=""
            />
          </div>
        </div>
        <div className="content-wrap">
          {/* 用户名 */}
          <div className="user-info">
            <div className="user-name">{item.user.uname}</div>
          </div>
          {/* 评论内容 */}
          <div className="root-reply">
            <span className="reply-content">{item.content}</span>
            <div className="reply-info">
              {/* 评论时间 */}
              <span className="reply-time">{item.ctime}</span>
              {/* 点赞数 */}
              <span className="reply-time">点赞数:{item.like}</span>
              {user.uid === item.user.uid && (
                <span
                  className="delete-btn"
                  onClick={() => onDelete(item.rpid)}
                >
                  删除
                </span>
              )}
            </div>
          </div>
        </div>
      </div>
    )
  })}
</div>

1. list.map(item => { ... })

1.1. map 函数

map 是 JavaScript 中数组的一个方法,用于遍历数组中的每个元素,并返回一个新的数组。map 方法接收一个回调函数作为参数,回调函数会对数组中的每个元素执行操作,然后返回新数组中的元素。具体语法如下:

const newArray = array.map(callback(element, index, array));
  • callback 是对每个元素执行的函数。
  • element 是当前处理的元素。
  • index 是当前元素的索引。
  • array 是被遍历的数组。

在这段代码中,map 方法用于遍历 list 数组中的每个 item,并返回包含 JSX 元素的数组。

1.2. 箭头函数 (item => { ... })

箭头函数是 ES6 中引入的一种更简洁的函数表达方式。箭头函数没有自己的 this 绑定,而是从作用域链的上一层继承 this。它的语法如下:

const functionName = (parameter) => { ... };

在这段代码中,箭头函数 item => { ... } 用于定义一个回调函数,其中 itemlist 数组中的每个元素。

2. return 语句

在箭头函数的回调函数内部,return 语句用于返回一个 JSX 元素,这个元素将被放入新的数组中。具体来说,return 语句返回了一个包含评论项的 div 元素。

3. JSX 语法

JSX 是 JavaScript 的一种语法扩展,用于描述 UI 结构。它看起来很像 HTML,但实际上是 React.createElement() 的语法糖。React 会将 JSX 代码转换为 JavaScript 对象,从而构建虚拟 DOM。

在这段代码中,JSX 用于描述每个评论项的结构。具体的 JSX 代码如下:

<div key={item.rpid} className="reply-item">
  {/* 列表项的内容 */}
</div>
  • key={item.rpid}key 属性是 React 中用于唯一标识每个列表项的标识符,有助于优化列表的渲染和更新。
  • className="reply-item"className 是 JSX 中用于指定 CSS 类名的属性,相当于 HTML 中的 class

4. 为什么这样设计

4.1. 使用 map 渲染列表

使用 map 函数渲染列表是一种常见的模式,因为它能够简洁而高效地遍历数组,并生成一组对应的 JSX 元素。每个元素都可以根据需要进行个性化渲染。

4.2. 使用 key 属性

在渲染列表时,React 需要一个唯一的 key 属性来区分不同的元素,从而高效地更新和重新渲染组件。key 属性的值应当是唯一的,且尽量稳定,以避免因重新渲染而导致的性能问题或潜在的 Bug。

4.3. 使用箭头函数

箭头函数使得代码更加简洁,同时避免了传统函数中的 this 绑定问题。在这个例子中,箭头函数用于定义 map 函数的回调,使得代码更易于阅读和维护。

5. 完整解读

{list.map(item => {
  return (
    <div key={item.rpid} className="reply-item">
      {/* 列表项的内容 */}
    </div>
  )
})}
  • list.map(item => { ... }):对 list 数组中的每个元素 item 执行回调函数。
  • return:返回一个包含评论项的 JSX 元素。
  • <div key={item.rpid} className="reply-item">...</div>:为每个评论项生成一个 div 元素,并指定唯一的 key 属性和 CSS 类名。

四、列表项的唯一标识

在渲染列表时,确保每个列表项都有一个唯一的key属性是至关重要的。这里使用评论的rpid作为key

<div key={item.rpid} className="reply-item">

1. key 的作用

当 React 渲染列表时,它需要一个唯一的标识符来跟踪每个元素,以便在元素发生变化时可以高效地重新渲染和更新。这主要体现在以下几个方面:

元素的识别

key 帮助 React 识别哪些元素发生了变化、被添加或被移除。例如,当我们有一个列表并对其进行重新排序时,key 使 React 能够知道哪些项是相同的,哪些项是新增的或删除的。

提高渲染性能

有了 key,React 可以根据变化最小化 DOM 操作。例如,如果一个列表项的位置发生了变化,而它的 key 没有变,React 只会移动 DOM 元素,而不是销毁旧元素并创建新元素,这大大提高了性能。

防止潜在的 Bug

没有 keykey 不唯一,可能导致一些潜在的 Bug。例如,输入框中的内容可能会丢失,组件的状态可能会出错等。key 保证了每个元素在其父元素中都是独一无二的,这样 React 就可以正确地维护和更新组件的状态。

2. key 的用法

在列表中使用 key 的典型方式如下:

<div key={item.rpid} className="reply-item">
  {/* 列表项的内容 */}
</div>

这里的 item.rpid 是一个唯一标识符,对于每个列表项来说都是独一无二的。

3. 可以没有 key 吗?

不能没有 key。如果不提供 key,React 会发出警告,告知 key 是必要的。即使不提供 key 的代码能够工作,它也会导致性能下降和潜在的 Bug。因此,始终建议在列表渲染中为每个元素提供一个唯一的 key

4. 示例代码中的 key

代码中,key 的用法如下:

{list.map(item => {
  return (
    <div key={item.rpid} className="reply-item">
      {/* 列表项的内容 */}
    </div>
  )
})}

这个 key={item.rpid} 确保了每个 reply-item 元素都有一个唯一标识符 rpid,这样 React 可以高效地更新和重新渲染评论列表。

五、处理评论删除

1. 删除评论的实现

在React中,要删除列表中的某个元素,可以使用数组的filter方法并调用setList来更新状态。以下是删除评论的实现代码:

const onDelete = rpid => {
  setList(list.filter(item => item.rpid !== rpid));
};

2. 条件渲染删除按钮

只有当前登录用户的评论才会显示删除按钮。这通过条件渲染来实现:

{user.uid === item.user.uid && (
  <span
    className="delete-btn"
    onClick={() => onDelete(item.rpid)}
  >
    删除
  </span>
)}
  1. 条件渲染
{user.uid === item.user.uid && ( ... )}

这一部分使用了逻辑与运算符(&&)来进行条件渲染。在JavaScript中,&&运算符在第一个操作数为真时返回第二个操作数,否则返回第一个操作数。在React的JSX语法中,这种写法常用于条件渲染。

  • user.uid:表示当前登录用户的ID。
  • item.user.uid:表示评论作者的ID。

这段代码的逻辑是:如果user.uid等于item.user.uid(即当前用户是评论的作者),则渲染<span>标签及其内容,否则不渲染任何内容。

  1. <span> 标签
<span
  className="delete-btn"
  onClick={() => onDelete(item.rpid)}
>
  删除
</span>

如果条件成立,这段代码将渲染一个<span>标签,具体解析如下:

className="delete-btn"

  • className:设置元素的CSS类。这里将<span>标签的CSS类设置为"delete-btn",以便应用相应的样式。

onClick={() => onDelete(item.rpid)}

  • onClick:React中的事件处理属性,用于处理点击事件。
  • {() => onDelete(item.rpid)}:这是一个箭头函数,点击时会调用onDelete函数,并传递当前评论的ID(item.rpid)作为参数。

当用户点击这个<span>标签时,onDelete函数会被调用,传递的rpid参数用于识别需要删除的评论。

箭头函数为什么设计成这样

  • 避免立即执行

如果直接写成 onClick={onDelete(item.rpid)},会导致在渲染时立即执行 onDelete 函数,而不是在点击时执行。这样会立即删除评论,而不是等待用户点击删除按钮。因此,需要使用一个函数包装起来,确保 onDelete(item.rpid) 只有在点击事件发生时才执行。

  • 创建事件处理函数

通过定义一个箭头函数 () => onDelete(item.rpid),我们创建了一个新的函数。当点击事件发生时,这个函数会被调用,然后再调用 onDelete 并传递参数 item.rpid

  1. 结合完整示例
  • 如果当前登录用户(user.uid)与评论的作者(item.user.uid)是同一个人,则渲染一个带有"delete-btn"类的<span>标签,显示“删除”文本。
  • 点击“删除”按钮时,调用onDelete函数,并传递当前评论的ID(item.rpid)以删除该评论。

六、完整代码示例

以下是包含所有上述功能的完整代码示例:

import { useState } from 'react';
import './App.scss';
import avatar from './images/bozai.png';
import orderBy from 'lodash/orderBy';

const defaultList = [
  {
    rpid: 3,
    user: {
      uid: '13258165',
      avatar: '',
      uname: '周杰伦',
    },
    content: '哎哟,不错哦',
    ctime: '10-18 08:15',
    like: 88,
  },
  {
    rpid: 2,
    user: {
      uid: '36080105',
      avatar: '',
      uname: '许嵩',
    },
    content: '我寻你千百度 日出到迟暮',
    ctime: '11-13 11:29',
    like: 88,
  },
  {
    rpid: 1,
    user: {
      uid: '30009257',
      avatar,
      uname: '黑马前端',
    },
    content: '学前端就来黑马',
    ctime: '10-19 09:00',
    like: 66,
  },
];

const user = {
  uid: '30009257',
  avatar,
  uname: '黑马前端',
};

const tabs = [
  { type: 'hot', text: '最热' },
  { type: 'time', text: '最新' },
];

const App = () => {
  const [activeTab, setActiveTab] = useState('hot');
  const [list, setList] = useState(defaultList);

  const onDelete = rpid => {
    setList(list.filter(item => item.rpid !== rpid));
  };

  const onToggle = type => {
    setActiveTab(type);
    let newList;
    if (type === 'time') {
      newList = orderBy(list, 'ctime', 'desc');
    } else {
      newList = orderBy(list, 'like', 'desc');
    }
    setList(newList);
  };

  return (
    <div className="app">
      <div className="reply-navigation">
        <ul className="nav-bar">
          <li className="nav-title">
            <span className="nav-title-text">评论</span>
            <span className="total-reply">{list.length}</span>
          </li>
          <li className="nav-sort">
            {tabs.map(item => {
              return (
                <div
                  key={item.type}
                  className={
                    item.type === activeTab ? 'nav-item active' : 'nav-item'
                  }
                  onClick={() => onToggle(item.type)}
                >
                  {item.text}
                </div>
              );
            })}
          </li>
        </ul>
      </div>

      <div className="reply-wrap">
        <div className="box-normal">
          <div className="reply-box-avatar">
            <div className="bili-avatar">
              <img className="bili-avatar-img" src={avatar} alt="用户头像" />
            </div>
          </div>
          <div className="reply-box-wrap">
            <textarea
              className="reply-box-textarea"
              placeholder="发一条友善的评论"
            />
            <div className="reply-box-send">
              <div className="send-text">发布</div>
            </div>
          </div>
        </div>
        <div className="reply-list">
          {list.map(item => {
            return (
              <div key={item.rpid} className="reply-item">
                <div className="root-reply-avatar">
                  <div className="bili-avatar">
                    <img
                      className="bili-avatar-img"
                      src={item.user.avatar}
                      alt=""
                    />
                  </div>
                </div>

                <div className="content-wrap">
                  <div className="user-info">
                    <div className="user-name">{item.user.uname}</div>
                  </div>
                  <div className="root-reply">
                    <span className="reply-content">{item.content}</span>
                    <div className="reply-info">
                      <span className="reply-time">{item.ctime}</span>
                      <span className="reply-time">点赞数:{item.like}</span>
                      {user.uid === item.user.uid && (
                        <span
                          className="delete-btn"
                          onClick={() => onDelete(item.rpid)}
                        >
                          删除
                        </span>
                      )}
                    </div>
                  </div>
                </div>
              </div>
            );
          })}
        </div>
      </div>
    </div>
  );
};

export default App;

源代码来源


在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1947943.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

SpringBoot整合Kaptcha实现图片验证码加减乘除

目录 SpringBoot整合Kaptcha实现图片验证码加减乘除1. 添加Kaptcha依赖2. 自定义文本生成器3. 配置Kaptcha4. 获取验证码图片的方法4.1. 详细讲解控制器中的切割操作 5. 总结 SpringBoot整合Kaptcha实现图片验证码加减乘除 在开发Web应用时&#xff0c;验证码是一个常见的功能…

Dhtmlx Gantt教程:创建交互式甘特图的完整指南

在现代的项目管理中&#xff0c;时间是一种宝贵的资源&#xff0c;而甘特图则是一把解锁项目进度的魔法钥匙&#xff0c;想象一下&#xff0c;您可以在一个直观而动态的时间轴上&#xff0c;清晰地看到项目的每一个任务如何交织在一起&#xff0c;如何随着时间的推移展开&#…

temu卖家中心入口登入在哪里,跨境电商temu卖家中心入口登入

在跨境电商的浪潮中&#xff0c;拼多多推出的Temu平台以其独特的商业模式和优惠政策&#xff0c;吸引了众多卖家的目光。对于想要入驻Temu平台的商家而言&#xff0c;找到正确的卖家中心入口并成功登录&#xff0c;是开启跨境电商之旅的第一步。那么&#xff0c;Temu卖家中心入…

QGC二次开发入门教程(一):课程大纲

文章目录 前言一、课程大纲二、修改软件名称三、修改软件图标四、官方QGC中文版BUG修复五、汉化六、修改商标七、添加信号-槽1、添加文件到QGC工程2、添加界面3、QML和C交互4、信号与槽5、测试 八、添加QML和C交互九、MAVLINK的解析与发送十、换地图十一、添加自定义mavlink消息…

3. 手势识别(LeNet、Vgg16、ResNet50)

手势识别 Show me your code1. 模型 model.py2. LeNet 实现手势识别&#xff08;详细&#xff09;2.1 数据打包2.2 搭建模型2.3 训练模型2.4 结果分析2.5 推理过程 3. Vgg16 手势识别4. ResNet50 手势识别 Show me your code 1. 模型 model.py import torch from torch impor…

基于单片机的智能台灯设计

摘 要 &#xff1a; 随着电子产品智能化的发展 &#xff0c; 生活中人们使用的照明工具也逐渐智能化 &#xff0c; 功能也越来越丰富 。 本文介绍了使用单片机进行可调光台灯系统的设计。 通过控制单片机输出高低电平的持续时间 &#xff0c; 从而改变 PWM 的占空比 &#…

el-tree树添加向下移动按钮,前端界面调整顺序

需求&#xff1a;树上添加向下按钮&#xff0c;再不调用接口的情况下&#xff0c;调整树的顺序结构 遇到的问题&#xff1a;第一次点击更新的&#xff0c;数据和视图是调整好的&#xff0c;再次点击页面调整顺序&#xff0c;只有数据被调整了&#xff0c;视图没有发生改变。 &…

【音视频之SDL2】bmp图片与绘制bmp

文章目录 前言BMP是什么SDL2绘制BMP的原理SDL2绘制BMP的流程SDL_LoadBMP作用函数原型参数返回值示例代码 SDL_BlitSurface作用函数原型参数返回值 示例代码效果展示总结 前言 在现代多媒体应用中&#xff0c;图像的处理和显示是非常重要的一部分。无论是在游戏开发还是在视频处…

Qt SQLite数据库编程学习总结

到此为止&#xff0c;就使用Qt进行SQLite数据库的操作&#xff0c;做一次总结 1. Qt中数据库操作的相关概念和类 Qt 数据库编程相关基本概念https://blog.csdn.net/castlooo/article/details/140497177 2.表的只读查询--QSqlQueryModel QSqlQueryModel单表查询的使用总结htt…

Nuxt.js 环境变量配置与使用

title: Nuxt.js 环境变量配置与使用 date: 2024/7/25 updated: 2024/7/25 author: cmdragon excerpt: 摘要&#xff1a;“该文探讨了Nuxt.js框架下环境变量配置的详细过程&#xff0c;涉及.env文件配置、运行时访问、安全性考量、在不同场景下的实践&#xff08;如Vue应用、…

华为OD机试 - 分配土地 (Java 2024年C卷D卷)

华为OD机试&#xff08;C卷D卷&#xff09;2024真题目录(Java & c & python) 题目描述 从前有个村庄&#xff0c;村民们喜欢在各种田地上插上小旗子&#xff0c;旗子上标识了各种不同的数字。 某天集体村民决定将覆盖相同数字的最小矩阵形的土地分配给村里做出巨大贡…

本地电脑连接阿里云

系列文章目录 提示&#xff1a;写完文章后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 系列文章目录前言一、方法1二、使用步骤1.引入库 前言 一、方法1 本地连接远程服务器的时候提示出现身份验证错误的几种解决方法 二、使用步骤 …

巴黎奥运启幕 PLM系统助力中国制造闪耀全球

2024巴黎奥运会将于法国当地时间7月26日在塞纳河畔正式开幕。即将亮相巴黎奥运会赛场的除了中国运动员之外&#xff0c;还有一批批中国制造企业为奥运会设计并制造的体育设备也将惊艳亮相&#xff0c;成为赛场上另一道亮丽的风景线。 在新时代的浪潮中&#xff0c;中国制造业坚…

大道云行,位居中国分布式存储市场挑战者象限!

近日&#xff0c;中国市场咨询机构赛迪顾问发布了《中国分布式存储市场研究报告&#xff08;2024&#xff09;》&#xff08;简称“报告”&#xff09;。报告基于对中国分布式存储市场的深入研究&#xff0c;从发展现状、厂商竞争力、未来趋势入手&#xff0c;结合新环境、新规…

【RHCE】综合真机实验(shell完成)

目录 题目&#xff1a; 需求描述 实操 一、服务端&#xff08;servera&#xff09; 1.ip配置 2.更改主机名 3.创建本地仓库 4.DNS服务 1.下载软件包和防火墙允许 2.配置主配置文件 3.配置区域文件 1.named.exam 2.named.fangxiang 4.重启服务 5.验证结果&#x…

OCDM水下通信仿真代码

一、代码介绍 MATLAB实现&#xff0c;基于OCDM水下基带通信仿真&#xff0c;对比了不同子载波激活的下OCDM水下通信性能&#xff0c;引入多径信道&#xff0c;采用相同信道估计方法,并对比了不同子载波数下的MMSE均衡效果。 信道估计方法参考论文 Robust Channel Estimation …

一款基于Cortex-M0+的单片机音频编解码 - CJC2100

USBCodec芯片可以对数字音频信号进行多种处理&#xff0c;例如增加音量、均衡调节、音效处理等。这些处理可以通过耳机的控制按钮来实现&#xff0c;让用户可以根据自己的喜好来调整音频效果。USBCodec芯片还可以控制噪声和失真的水平&#xff0c;以提供高品质的音频输出。噪声…

单证不一致清关难题 | 国际贸易综合服务平台 | 箱讯科技

什么是单证一致&#xff1f; 单证一致出口方所提供的所有单据要严格符合进口方开证银行所开信用证的要求&#xff0c;或者说出口方制作和提供的所有与本项货物买卖有关的单据&#xff0c;与进口方申请开立的信用证对单据的要求完全吻合&#xff0c;没有矛盾。 添加图片注释&am…

batch norm记录

文章目录 概要整体架构流程训练阶段推理阶段模型中使用的注意事项 概要 面试百度时候被问到了BN 内部详细的训练阶段&#xff0c;推理阶段的计算过程。没回答好&#xff0c;来记录一下 推荐一下b站up: Enzo_Mi。视频做的确实不错 bn 讲解视频 整体架构流程 训练阶段 均值和标…

多模态大模型技术白皮书 2024

不同于语言大模型只对文本进行处理&#xff0c;多模态大模型将文本、语音、图像、视频等多模态数据联合起来进行学习。多模态大模型融合了多种感知途径与表达形态&#xff0c;能够同时处理和理解来自不同感知通道&#xff08;例如视觉、听觉、语言和触觉等&#xff09;的信息&a…