文章目录
原代码
import './App.scss'
import avatar from './images/bozai.png'
import { useState } from 'react'
/**
* 评论列表的渲染和操作
*
* 1. 根据状态渲染评论列表
* 2. 删除评论
*/
// 评论列表数据
const defaultList = [
{
// 评论id
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 = {
// 用户id
uid: '30009257',
// 用户头像
avatar,
// 用户昵称
uname: '黑马前端',
}
/**
* 导航 Tab 的渲染和操作
*
* 1. 渲染导航 Tab 和高亮
* 2. 评论列表排序
* 最热 => 喜欢数量降序
* 最新 => 创建时间降序
*/
// 导航 Tab 数组
const tabs = [
{ type: 'hot', text: '最热' },
{ type: 'time', text: '最新' },
]
// 2、使用useEffect 监听评论列表数据的变化
// 3、使用useRef 管理评论列表的滚动位置
// 4、使用useCallback 管理评论列表的滚动位置
// 5、使用useMemo 管理评论列表的滚动位置
// 6、使用useContext 管理评论列表的滚动位置
// 7、使用useReducer 管理评论列表的滚动位置
const App = () => {
// 渲染评论列表
// 1、使用useState 管理评论列表数据
const [commentList, setCommentList] = useState(defaultList)
// 删除评论
const handleDelete = (rpid) => {
// 过滤掉要删除的评论
// 使用filter 方法过滤掉要删除的评论
// filter 方法会返回一个新数组,新数组中不包含要删除的评论
// 新数组中的元素是原数组中除了要删除的评论以外的所有元素
// 使用setCommentList 方法更新评论列表数据
setCommentList(commentList.filter(item => item.rpid !== rpid))
}
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 */}
<span className='nav-item'>最新</span>
<span className='nav-item'>最热</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">
{/* 评论框 */}
<textarea
className="reply-box-textarea"
placeholder="发一条友善的评论"
/>
{/* 发布按钮 */}
<div className="reply-box-send">
<div className="send-text">发布</div>
</div>
</div>
</div>
{/* 评论列表 */}
<div className="reply-list">
{/* 评论项 */}
{commentList.map(item => (
<div key={item.rpid} className="reply-item">
{/* 头像 */}
<div className="root-reply-avatar">
<div className="bili-avatar">
<img
className="bili-avatar-img"
alt=""
src={item.user.avatar
|| 'https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/72x72/1f464.png'}
/>
</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>
{/* 删除按钮 */}
{/* 判断是否是当前登录用户 */}
{item.user.uid === user.uid && (
<span className="delete-btn" onClick={() => handleDelete(item.rpid)}>
删除
</span>
)}
</div>
</div>
</div>
</div>
))}
</div>
</div>
</div>
)
}
export default App
问:为什么删除评论是客户端调用过滤评论,而不是请求数据库删除,然后再从数据库获取最新评论列表呢?
答
这是一个很好的问题!让我来解释一下这两种删除评论的实现方式:
当前代码的实现方式(本地状态管理)
const handleDelete = (rpid) => {
setCommentList(commentList.filter(item => item.rpid !== rpid))
}
这种方式是客户端状态管理,直接修改本地的状态数据。
两种方式的对比
1. 本地过滤方式(当前代码)
优点:
- 🚀 响应速度快 - 无需等待网络请求
- 💰 节省服务器资源 - 减少API调用次数
- 🎯 用户体验好 - 立即反馈,无加载等待
缺点:
- ⚠️ 数据不同步 - 只是前端展示删除,后端数据库还存在
- 🔄 页面刷新后恢复 - 数据会重新从服务器加载
2. API删除方式(你提到的方式)
const handleDelete = async (rpid) => {
try {
// 1. 调用删除API
await deleteCommentAPI(rpid)
// 2. 重新获取评论列表
const newList = await getCommentsAPI()
setCommentList(newList)
} catch (error) {
console.error('删除失败:', error)
}
}
优点:
- ✅ 数据真实同步 - 前后端数据一致
- 🔒 数据持久化 - 删除后数据真正消失
缺点:
- 🐌 响应较慢 - 需要等待两次网络请求
- 💸 服务器负担重 - 每次操作都需要API调用
实际项目中的最佳实践
在真实项目中,通常会采用混合方式:
const handleDelete = async (rpid) => {
try {
// 1. 立即更新UI(乐观更新)
setCommentList(commentList.filter(item => item.rpid !== rpid))
// 2. 后台调用删除API
await deleteCommentAPI(rpid)
// 3. 如果删除失败,恢复UI状态
} catch (error) {
// 恢复删除的评论
setCommentList(originalList)
alert('删除失败,请重试')
}
}
总结
当前代码可能是:
- 学习Demo - 专注于React状态管理学习
- 原型阶段 - 还未连接后端服务
- 离线应用 - 数据只在本地存储
在实际生产环境中,建议使用乐观更新的方式,既保证用户体验,又确保数据一致性!