如何在React UI中实时显示点赞与点踩计数?
解决React点赞点踩后UI不实时更新的问题
你的问题核心是:点赞/点踩请求成功后,没有更新组件内的帖子数据,导致UI仍使用初始的props值,必须刷新页面重新获取数据才会更新。下面是具体的修复方案:
修复步骤:
- 将传入的
postprops存入组件内部的state,让组件能手动更新数据 - 监听
postprops的变化,确保外部数据更新时组件内的state同步 - 在点赞/点踩请求成功后,用后端返回的最新帖子数据更新state
- 修正点踩功能的图标判断逻辑(原代码错误使用了
likes数组判断点踩状态)
修改后的完整代码:
import React, { useEffect, useState } from "react"; import axios from "axios"; import * as timeago from "timeago.js"; import { Link } from "react-router-dom"; import MoreVertRoundedIcon from "@mui/icons-material/MoreVertRounded"; import ThumbUpOutlinedIcon from "@mui/icons-material/ThumbUpOutlined"; import ThumbUpAltRoundedIcon from "@mui/icons-material/ThumbUpAltRounded"; import ThumbDownOffAltRoundedIcon from "@mui/icons-material/ThumbDownOffAltRounded"; import ThumbDownAltRoundedIcon from "@mui/icons-material/ThumbDownAltRounded"; import CommentRoundedIcon from "@mui/icons-material/CommentRounded"; import { useContext } from "react"; import { AuthContext } from "../../context/AuthContext"; const Post = ({ post }) => { const [user, setUser] = useState({}); // 将props的post存入内部state const [currentPost, setCurrentPost] = useState(post); const { user: currentUser } = useContext(AuthContext); const likePost = async () => { try { // 请求后获取后端返回的更新后帖子数据 const response = await axios.put(`/post/${currentPost?._id}/like`, { userId: currentUser._id }); // 更新本地state,触发UI重新渲染 setCurrentPost(response.data); } catch (error) { console.error("点赞失败:", error); // 不要忽略错误,便于调试 } }; const dislikePost = async () => { try { const response = await axios.put(`/post/${currentPost?._id}/dislike`, { userId: currentUser._id, }); setCurrentPost(response.data); } catch (error) { console.error("点踩失败:", error); } }; useEffect(() => { const fetchUser = async () => { const response = await axios.get(`/users?userId=${currentPost.userId}`); setUser(response.data); }; fetchUser(); }, [currentPost.userId]); // 监听外部props的post变化,同步到内部state useEffect(() => { setCurrentPost(post); }, [post]); return ( <div className="post"> <div className="post-top"> <div className="user"> <Link to={`/profile/${user?.username}`} style={{ color: "inherit", textDecoration: "none" }} > <img src={ user?.profilePicture ? user?.profilePicture : "https://thumbs.dreamstime.com/b/no-user-profile-picture-24185395.jpg" } alt="" /> </Link> <div className="user-info"> <Link to={`/profile/${user?.username}`} style={{ color: "inherit", textDecoration: "none" }} > <span className="username">{user?.username}</span> </Link> <span>{timeago.format(currentPost.createdAt)}</span> </div> </div> <div> <MoreVertRoundedIcon style={{ cursor: "pointer" }} /> </div> </div> {currentPost?.image ? <hr /> : <hr style={{ display: "none" }} />} <div className="post-center"> {currentPost?.image ? ( <img src={currentPost?.image} alt="" /> ) : ( <img style={{ display: "none" }} /> )} </div> <div className="post-desc"> <div className="description"> <span>{user?.username}</span> <span>{currentPost?.description}</span> </div> </div> <div className="post-bottom"> <div className="icons" onClick={likePost}> {currentPost?.likes.includes(currentUser?._id) ? <ThumbUpAltRoundedIcon /> : <ThumbUpOutlinedIcon /> } <span>{currentPost?.likes.length}</span> </div> <div className="icons" onClick={dislikePost}> {/* 修正:使用dislikes数组判断点踩状态 */} {currentPost?.dislikes.includes(currentUser?._id) ? <ThumbDownAltRoundedIcon /> : <ThumbDownOffAltRoundedIcon />} <span>{currentPost?.dislikes.length}</span> </div> <div className="icons"> <CommentRoundedIcon /> <span>10</span> </div> </div> </div> ); }; export default Post;
额外说明:
- 如果你的Post组件是在列表中渲染(比如PostList组件循环渲染多个Post),更优的做法是在父组件中维护整个帖子列表的state,点赞/点踩时调用父组件传递的更新方法来修改列表中的对应帖子,这样能保证所有引用该帖子的地方都同步更新。
- 永远不要忽略catch块的错误处理,添加日志能帮你快速定位问题。
内容的提问来源于stack exchange,提问作者Jaif Md
相关产品推荐
相关产品推荐

