当前位置: 首页 > java >正文

React实现B站评论Demo

该Demo涉及的技术点

  • useState函数(数据驱动视图)
  • 子组件的封装
  • 条件判断
  • 回调函数的封装

1、评论数据

{"list": [{"rpid": 3,"user": {"uid": "13258165","avatar": "http://toutiao.itheima.net/resources/images/98.jpg","uname": "周杰伦"},"content": "哎哟,不错哦","ctime": "10-18 08: 15","like": 126},{"rpid": 2,"user": {"uid": "36080105","avatar": "http://toutiao.itheima.net/resources/images/98.jpg","uname": "许嵩"},"content": "我寻你千百度 日出到迟暮","ctime": "11-13 11: 29","like": 88},{"rpid": 1,"user": {"uid": "30009257","avatar": "http://toutiao.itheima.net/resources/images/98.jpg","uname": "前端"},"content": "前端真好玩","ctime": "10-19 09: 00","like": 66}]
}

2、具体实现

  • 获取json中的list数据 (读取本地文件 / 读取接口)
const JsonReader = () => {// 定义一个数组状态来存储 JSON 数据const [ commentList, setCommentList ] = useState([]);// 使用 useEffect 钩子来加载 JSON 文件useEffect(() => {// 使用 fetch API 读取 JSON 文件 , 这里需要注意,json文件读取的根路径是public路径fetch('_db.json').then(response => {if (!response.ok) {throw new Error('Network response was not ok');}return response.json(); // 解析 JSON 数据}).then(data => {// console.log(data)// 将解析后的 JSON 数据存储到 list 数组中setCommentList(_.orderBy(data.list, 'like', 'desc'));}).catch(error => {console.error('There has been a problem with your fetch operation:', error);});}, []); // 空依赖数组表示只在组件挂载时执行一次return {commentList, setCommentList}
}// 封装请求数据的Hook
function useGetList () {// 获取接口数据渲染const [commentList, setCommentList] = useState([])useEffect(() => {// 请求数据async function getList () {// axios请求数据const res = await axios.get(' http://localhost:3004/list')setCommentList(res.data)}getList()}, [])return {commentList,setCommentList}
}
  • 封装用户信息、导航栏
// 当前登录用户信息
const user = {// 用户iduid: '30009257',// 用户头像avatar,// 用户昵称uname: '黑马前端',
}
// 导航 Tab 数组
const tabs = [{ type: 'hot', text: '最热' },{ type: 'time', text: '最新' },
]
  • 封装单个评论组件
// 封装Item组件
function Item ({ item, onDel }) {return (<div className="reply-item">{/* 头像 */}<div className="root-reply-avatar"><div className="bili-avatar"><imgclassName="bili-avatar-img"alt=""src={item.user.avatar}/></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.id === item.user.id */}{user.uid === item.user.uid &&<span className="delete-btn" onClick={() => onDel(item.rpid)}>删除</span>}</div></div></div></div>)
}
  • 最终实现
const App = () => {// 渲染评论列表// 1. 使用useState维护list// const [commentList, setCommentList] = useState(_.orderBy(List, 'like', 'desc'))// const { commentList, setCommentList } = useGetList()const { commentList, setCommentList } = JsonReader()// 删除功能const handleDel = (id) => {console.log(id)// 对commentList做过滤处理setCommentList(commentList.filter(item => item.rpid !== id))}// tab切换功能// 1. 点击谁就把谁的type记录下来// 2. 通过记录的type和每一项遍历时的type做匹配 控制激活类名的显示const [type, setType] = useState('hot')const handleTabChange = (type) => {console.log(type)setType(type)// 基于列表的排序if (type === 'hot') {// 根据点赞数量排序 // lodashsetCommentList(_.orderBy(commentList, 'like', 'desc'))} else {// 根据创建时间排序setCommentList(_.orderBy(commentList, 'ctime', 'desc'))}}// 发表评论const [content, setContent] = useState('')const inputRef = useRef(null)const handlPublish = () => {setCommentList([...commentList,{rpid: uuidV4(), // 随机iduser: {uid: '30009257',avatar,uname: '黑马前端',},content: content,ctime: dayjs(new Date()).format('MM-DD hh:mm'), // 格式化 月-日 时:分like: 66,}])// 1. 清空输入框的内容setContent('')// 2. 重新聚焦  dom(useRef) - focusinputRef.current.focus()}return (<div className="app">{/* 导航 Tab */}<div className="reply-navigation"><ul className="nav-bar"><li className="nav-title"><span className="nav-title-text">评论</span>{/* 评论数量 */}<span className="total-reply">{10}</span></li><li className="nav-sort">{/* 高亮类名: active */}{tabs.map(item =><spankey={item.type}onClick={() => handleTabChange(item.type)}className={classNames('nav-item', { active: type === item.type })}>{item.text}</span>)}</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">{/* 评论框 */}<textareaclassName="reply-box-textarea"placeholder="发一条友善的评论"ref={inputRef}value={content}onChange={(e) => setContent(e.target.value)}/>{/* 发布按钮 */}<div className="reply-box-send"><div className="send-text" onClick={handlPublish}>发布</div></div></div></div>{/* 评论列表 */}<div className="reply-list">{/* 评论项 */}{commentList.map(item => <Item key={item.id} item={item} onDel={handleDel} />)}</div></div></div>)
}

最终效果:
在这里插入图片描述

http://www.xdnf.cn/news/3837.html

相关文章:

  • 分布式系统中的 ActiveMQ:异步解耦与流量削峰(一)
  • Dify 完全指南(一):从零搭建开源大模型应用平台(Ollama/VLLM本地模型接入实战)》
  • Github2025-05-04php开源项目日报 Top10
  • 详解迁移学习,模型参数冻结,优化器参数定义
  • 传感器数据处理笔记
  • Linux中的粘滞位和开发工具和文本编辑器vim
  • 马小帅面试遇“灵魂拷问“
  • hot100:链表倒数k个节点- 力扣(LeetCode)
  • 研0大模型学习(第11天)
  • FFT实现(Cooley-Tukey算法)
  • WEB 前端学 JAVA(二)Java 的发展与技术图谱简介
  • TS 字面量类型
  • Mybatis学习(下)
  • LabVIEW开发风量智能监测系统
  • 【杂谈】-探索 NVIDIA Dynamo 的高性能架构
  • 牛客周赛90 C题- Tk的构造数组 题解
  • STM32智能垃圾桶:四种控制模式实战开发
  • 58认知干货:创业经验分享及企业形式的汇总
  • 【AI面试准备】逻辑思维、严谨性、总结能力、沟通协作、适应力与目标导向
  • 文件一键解密软件工具(支持pdf、word、excel、ppt、rar、zip格式文件)
  • 链接文件及功能安全:英飞凌官方文档摘录 - Tasking链接文件
  • 开上“Python跑的车”——自动驾驶数据可视化的落地之道
  • 使用python写多文件#inlcude
  • Spring AI Advisors API:AI交互的灵活增强利器
  • ES6入门---第三单元 模块三:async、await
  • 网络:TCP三次握手、四次挥手
  • 介词:连接名词与句子其他成分的桥梁
  • 互联网大厂Java面试:从基础到实战
  • 【漫话机器学习系列】239.训练错误率(Training Error Rate)
  • vulkanscenegraph显示倾斜模型(6.4)-多线程下的记录与提交