【综合案例】使用React编写B站评论案例

一、效果展示

默认效果,一开始默认按照最热进行排序
发布了一条评论
按照最新进行排序
按照最新进行排序

二、效果说明

页面上默认有3条评论,且一开始进入页面的时候是按照点赞数量进行倒序排列展示,可以点击【最热 、最新】进行排序的切换。

在文本框中输入要评论的文本,然后点击【发布】按钮,即可将评论添加到下方的评论列表当中进行展示;如果没有输入任何文本的时候直接点击【发布】按钮会弹出提示对话框。

点击删除按钮可以将对应的评论从评论列表中移除。

三、涉及知识点

3.1 useState

3.1.1 基础使用

useState 是一个 React Hook(函数),它允许我们向组件添加一个状态变量, 从而控制影响组件的渲染结果。

🚩 语法:

const [state, setState] = useState(initialState)
  1. useState是一个函数,返回值是一个数组 
  2. 数组中的第一个参数是状态变量;第二个参数是set函数,用来修改状态变量
  3. useState的参数将作为state的初始值

🚩 本质:

和普通JS变量不同的是,状态变量一旦发生变化组件的视图UI也会跟着变化(数据驱动视图)。

注意事项:

  • useState 是一个 Hook,因此你只能在 组件的顶层 或自己的 Hook 中调用它。你不能在循环或条件语句中调用它。如果你需要这样做,请提取一个新组件并将状态移入其中。
  • 在严格模式中,React 将 两次调用初始化函数,以 帮你找到意外的不纯性。这只是开发时的行为,不影响生产。如果你的初始化函数是纯函数(本该是这样),就不应影响该行为。其中一个调用的结果将被忽略。
3.1.2 修改状态的规则

🚩 状态不可变

在React中,状态被认为是只读的,我们应该始终 替换它而不是修改它, 直接修改状态不能引发视图更新。

🚩 修改对象状态

规则:对于对象类型的状态变量,应该始终传给set方法一个 全新的对象 来进行修改。

3.2  classnames优化类名控制

classnames是一个简单的JS库,可以非常方便的 通过条件动态控制class类名的显示。

 

现在的问题:字符串的拼接方式不够直观,也容易出错。
3.3 受控表单绑定

 概念:使用React组件的状态(useState)控制表单的状态。

 1. 准备一个React状态值

const [value, setValue] = useState('')
2. 通过value属性绑定状态,通过onChange属性绑定状态同步的函数
// 通过value属性绑定react状态
// 绑定onChange事件,通过事件参数e拿到输入框最新的值,反向修改到react状态
<inputtype="text"value={value}onChange={(e) => setValue(e.target.value)}/>
3.4  获取DOM

在React组件中获取 / 操作DOM,需要使用useRef React Hook钩子函数,分为两步:

1. 使用useRef创建 ref 对象,并与 JSX 绑定

2. 在DOM可用时,通过 inputRef.current 拿到 DOM 对象

四、代码实现

4.1 逻辑渲染层

import { useRef, useState } from "react";
import './App.scss'
import avatar from './image/bozai.png'
import dayjs from 'dayjs'
import { v4 as uuidV4 } from 'uuid'
import _ from 'lodash'
import classNames from 'classnames'
function App() {// 当前登录用户信息const user = {// 用户iduid: '30009257',// 用户头像avatar,// 用户昵称uname: '嘟嘟嘟',}// 评论列表数据const defaultList = [{// 评论idrpid: 3,// 用户信息user: {uid: '13258165',avatar: require('./image/panda.jpg'),uname: '周杰伦',},// 评论内容content: '哎哟,不错哦',// 评论时间ctime: '10-18 08:15',like: 88,},{rpid: 2,user: {uid: '36080105',avatar: require('./image/panda.jpg'),uname: '许嵩',},content: '我寻你千百度 日出到迟暮',ctime: '11-13 11:29',like: 88,},{rpid: 1,user: {uid: '30009257',avatar,uname: '黑马前端',},content: '学前端就来黑马',ctime: '10-19 09:00',like: 66,},]// 导航 Tab 数组const tabs = [{ type: 'hot', text: '最热' },{ type: 'time', text: '最新' },]// 最初的时候先按照最热进行倒叙排列const [remarkList, setRemark] = useState(_.orderBy(defaultList, 'hot', 'desc'))const [content, setContent] = useState('')const inputRef = useRef(null)// 发布评论function handleSubmit() {// 阻止提交空数据if (!content) return alert('请输入评论内容')setRemark([{rpid: uuidV4(),//随机iduser,content,ctime: dayjs(new Date()).format('MM-DD HH:mm'),like: 0,},...remarkList])setContent('')//清空输入框中的内容inputRef.current?.focus()//重新聚焦}// 删除评论function handleDel(item) {setRemark(remarkList.filter(v => v.rpid !== item.rpid))}const [type, setType] = useState('hot')/*** tab切换*  1.点击谁就把谁的type记录下来*  2.通过记录的type和每一项遍历时的type做匹配,控制激活类名的显示*/function handleTabChange(type) {setType(type)if (type === 'time') {// 按照时间倒序setRemark(_.orderBy(remarkList, 'ctime', 'desc'))} else {// 按照点赞数倒序setRemark(_.orderBy(remarkList, 'like', 'desc'))}}return (<div className="App"><div className="top"><div className="left"><span className="l-title">评论</span><span>{remarkList.length}</span></div><div className="right">{/* 高亮类名 */}{/* classnames优化类名控制classnames是一个简单的JS库,可以非常方便的通过条件动态控制class类型的显示*/}{tabs.map((item) => {return (<spanclassName={classNames('nav-item', { active: type === item.type })}key={item.type}onClick={() => handleTabChange(item.type)}>{item.text}</span>)})}</div></div><div className="push"><img className="avatar" src={user.avatar} /><textarea className="textarea" placeholder="发一条友善的评论" ref={inputRef} value={content} onChange={(e) => setContent(e.target.value)}></textarea><button className="pushBtn" onClick={handleSubmit}>发布</button></div><div className="main">{/* 评论项 */}{remarkList.map((item) => {return (<div className="m-item" key={item.rpid}><img className="avatar" src={item.user.avatar} /><div className="mi-right"><div>{item.user.uname}</div><div className="text">{item.content}</div><div ><span>{item.ctime}</span><span className="like">点赞数:{item.like}</span><span onClick={() => handleDel(item)}>删除</span></div></div></div>)})}</div></div>);
}export default App;

4.2 样式层

.App{margin: 10px;
}
.top{margin-bottom: 20px;display: flex;align-items: baseline;font-size: 15px;color: #999;
.left{margin-right: 50px;
.l-title{font-size: 20px;font-weight: 700;color: #000;margin-right: 5px;
}
}
.right{display: flex;flex-direction: row;align-items: center;.nav-item {cursor: pointer;&:hover {color: #00aeec;}&:last-child::after {display: none;}&::after {content: ' ';display: inline-block;height: 10px;width: 1px;margin: -1px 12px;background-color: #9499a0;}}.nav-item.active{color: #000;}
}
}
.push{margin-bottom: 20px;display: flex;
.textarea{margin: 0 10px;padding: 10px;flex: 1;min-height: 30px;max-height: 100px;border-radius: 10px;border: none;outline: none;background-color: #ebebeb;
}
.pushBtn{width: 100px;height: 50px;font-size: 16px;color: #fff;border: none;border-radius: 5px;background-color: rgba(0,174,236,0.5);&:hover{background-color: rgba(0,174,236);}
}
}
.avatar{width: 40px;height: 40px;border-radius: 50%;
}.m-item{display: flex;margin-bottom: 10px;
.mi-right{padding-bottom: 10px;margin-left: 10px;flex: 1;font-size: 14px;color: #999;border-bottom: 1px solid #e4e3e3;
}
.text{margin: 10px 0;color: #000;
}
.like{margin: 0 20px;
}
}

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

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

相关文章

docker镜像文件导出导入

1. 导出容器&#xff08;包含内部服务&#xff09;为镜像文件&#xff08;docker commit方法&#xff09; 原理&#xff1a;docker commit命令允许你将一个容器的当前状态保存为一个新的镜像。这个新镜像将包含容器内所有的文件系统更改&#xff0c;包括安装的软件、配置文件等…

区块链技术与应用-PKU 学习笔记

课程地址 资料&#xff1a; ETH-Security 区块链学习记录_比特币 BTC 密码学原理 比特币&#xff0c;又称加密货币(crypto-currency)&#xff0c;它主要利用了密码学中的哈希函数(cryptographic hash function)的抗碰撞特性(collision resistance)和单向散列特性(hiding) …

在Java中,实现数据库连接通常使用JDBC

学习总结 1、掌握 JAVA入门到进阶知识(持续写作中……&#xff09; 2、学会Oracle数据库入门到入土用法(创作中……&#xff09; 3、手把手教你开发炫酷的vbs脚本制作(完善中……&#xff09; 4、牛逼哄哄的 IDEA编程利器技巧(编写中……&#xff09; 5、面经吐血整理的 面试技…

【优选算法 — 双指针】双指针小专题

和为 s 的两个数 和为s的两个数 题目描述 解法一&#xff1a;暴力枚举 暴力枚举&#xff0c;先固定一个数&#xff0c;然后让这个数和另一个数匹配相加&#xff0c; 如果当前的数 所有剩余的数 target&#xff0c;则返回这两个数&#xff0c;否则固定下一个数&#…

并查集(基础学习与应用)

并查集 基本原理&#xff1a; 对于多个集合&#xff0c;每个集合中的多个元素用一颗树的形式表示&#xff0c;根节点的编号即为整个集合的编号&#xff0c;每个树上节点存储其父节点&#xff0c;使得当前集合的每个子节点都可以通过对父节点的询问来找到根节点&#xff0c;根…

003-Kotlin界面开发之声明式编程范式

概念本源 在界面程序开发中&#xff0c;有两个非常典型的编程范式&#xff1a;命令式编程和声明式编程。命令式编程是指通过编写一系列命令来描述程序的运行逻辑&#xff0c;而声明式编程则是通过编写一系列声明来描述程序的状态。在命令式编程中&#xff0c;程序员需要关心程…

Spring Boot 与 Vue 共筑地方特色美食分享卓越平台

作者介绍&#xff1a;✌️大厂全栈码农|毕设实战开发&#xff0c;专注于大学生项目实战开发、讲解和毕业答疑辅导。 &#x1f345;获取源码联系方式请查看文末&#x1f345; 推荐订阅精彩专栏 &#x1f447;&#x1f3fb; 避免错过下次更新 Springboot项目精选实战案例 更多项目…

react使用Fullcalendar 实战用法

使用步骤请参考&#xff1a;react使用Fullcalendar 卡片式的日历&#xff1a; 需求图&#xff1a; 卡片式的日历&#xff0c;其实我是推荐 antd的&#xff0c;我两个都写了一下都能实现。 antd 的代码&#xff1a; antd的我直接用的官网示例&#xff1a;antd 日历示例 i…

Flutter 正在切换成 Monorepo 和支持 workspaces

其实关于 Monorepo 和 workspaces 相关内容在之前《Dart 3.5 发布&#xff0c;全新 Dart Roadmap Update》 和 《Flutter 之 ftcon24usa 大会&#xff0c;创始人分享 Flutter 十年发展史》 就有简单提到过&#xff0c;而目前来说刚好看到 flaux 这个新进展&#xff0c;所以就再…

在做题中学习(74):比较含退格的字符串

解法&#xff1a;用栈来模拟 思路&#xff1a;不用真的定义一个栈,用字符串string来模拟栈的行为 入栈&#xff1a;s[i] ! #时 push_back(s[i]) 出栈:s[i] # 的时候&#xff0c;并且s.size() > 0&#xff0c;pop_back(s[i])循环结束得到结果 注意&#xff1a;如果真的…

前后端交互通用排序策略

目录 排序场景 排序实现思路 1. 静态代码排序实现 2.数据库驱动排序实现 3. 基于Java反射的动态排序实现 通用排序工具 SortListUtil 结语 排序场景 在面向前端数据展示的应用场景中&#xff0c;我们旨在实现一个更加灵活的排序机制&#xff0c;该机制能够支持对从后端传递…

MD5(Crypto)

解题思路 打开文件发现一串代码&#xff0c;结合题目提示&#xff0c;应该是 MD5 加密。 找个在线的 MD5 解密网站&#xff0c;行云流水得到 flag。 题目设计原理 题目设计&#xff1a;无他&#xff0c;MD5 加密。 题目原理&#xff1a; MD5&#xff08;Message-Digest Algo…

跟李沐学AI:BERT

什么是NLP中的迁移学习 使用预训练好的模型来抽取词、句子的特征&#xff1a;Word2Vec或者预训练好的语言模型。 使用预训练好的语言模型&#xff0c;一般不会再对语言模型进行微调&#xff0c;即不进行更新。 Word2Vec一般用于替代embedding层 但是Word2Vec往往忽略了时序…

单元/集成测试解决方案

在项目开发的前期针对软件单元/模块功能开展单元/集成测试&#xff0c;可以尽早地发现软件Bug&#xff0c;避免将Bug带入系统测试阶段&#xff0c;有效地降低HIL测试的测试周期&#xff0c;也能有效降低开发成本。单元/集成测试旨在证明被测软件实现其单元/架构设计规范、证明被…

C语言复习第9章 字符串/字符/内存函数

目录 一、字符串函数1.1 读取字符串gets函数原型Example 1.2 字符串拷贝strcpy函数原型模拟实现官方源码 1.3 求字符串长度strlen函数原型关于返回值size_与算术转换的一个易错点模拟实现:递归模拟实现:指针-指针模拟实现:暴力官方源码 1.4 字符串追加strcat函数原型注意自己给…

WPF 特性------Binding

工业控制中&#xff0c;经常会需要把一个bool 型输入信号的状态显示在面板上&#xff0c;使用wpf 绑定的办法&#xff0c;可简洁实现&#xff1a; 实现步骤&#xff1a; 1&#xff0c;定义类&#xff1a; using System; using System.Collections.Generic; using System.Com…

【MySQL】深层理解索引及特性(重点)--下(12)

索引&#xff08;重点&#xff09; 1. 索引的作用2. 索引操作2.1 主键索引2.1.1 主键索引的特点2.1.2 创建主键索引 2.2 唯一键索引2.2.1 唯一键索引的特点2.2.2 唯一索引的创建 2.3 普通索引2.3.1 普通索引的特点2.3.2 普通索引的创建 2.4 全文索引2.4.1 全文索引的作用2.4.2 …

基于SpringBoot+微信小程序+协同过滤算法+二维码订单位置跟踪的农产品销售平台-新

✌全网粉丝20W,csdn特邀作者、博客专家、CSDN新星计划导师、java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取项目下载方式&#x1f345; 一、项目背景介绍&#xff1a; “农产品商城”小程序…

C++ | Leetcode C++题解之第541题反转字符串II

题目&#xff1a; 题解&#xff1a; class Solution { public:string reverseStr(string s, int k) {int n s.length();for (int i 0; i < n; i 2 * k) {reverse(s.begin() i, s.begin() min(i k, n));}return s;} };

一个由Deno和React驱动的静态网站生成器

大家好&#xff0c;今天给大家分享一个由 Deno React 驱动的静态网站生成器Pagic。 项目介绍 Pagic 是一个由 Deno React 驱动的静态网站生成器。它配置简单&#xff0c;支持将 md/tsx 文件渲染成静态页面&#xff0c;而且还有大量的官方或第三方主题和插件可供扩展。 核心…