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

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>)
}

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

相关文章:

  • Linux环境部署iview-admin项目
  • 智能工厂自主优化:从局部调优到全局演进
  • 【中间件】brpc_基础_用户态线程中断
  • 小程序 IView WeappUI组件库(简单增删改查)
  • iview 表单验证问题 Select 已经选择 还是弹验证提示
  • Qt实现 hello world + 内存泄漏(5)
  • Qt基础知识记录(终篇)
  • cloudfare+gmail 配置 smtp 邮箱
  • GPU集群训练经验评估框架:运营经理经验分析篇
  • load_dotenv()详解
  • 《算法导论(第4版)》阅读笔记:p6-p6
  • GCC 使用指南
  • idea创建springboot工程-指定阿里云地址创建工程报错
  • Spring AI聊天模型API:轻松构建智能聊天交互
  • 每日c/c++题 备战蓝桥杯(洛谷P1190 [NOIP 2010 普及组] 接水问题)
  • 【心海资源】子比主题新增注册与会员用户展示功能模块及实现方法
  • Maven框架详解:构建与依赖管理的利器
  • Linux 入门:操作系统进程详解(上)
  • ARM Linux 设备树
  • 视频编解码学习三之显示器
  • 体坛联播|拜仁提前2轮德甲夺冠,赵心童11比6暂时领先
  • 2年就过气!ChatGPT催生的百万年薪岗位,大厂不愿意招了
  • 3:0战胜日本队,中国羽毛球队挺进2025苏迪曼杯决赛
  • 哈马斯:愿与以色列达成为期5年的停火协议
  • 首日5金!中国队夺得跳水世界杯总决赛混合团体冠军
  • 燕子矶:物流网络中的闪亮节点|劳动者的书信②