You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在React UI中实时显示点赞与点踩计数?

解决React点赞点踩后UI不实时更新的问题

你的问题核心是:点赞/点踩请求成功后,没有更新组件内的帖子数据,导致UI仍使用初始的props值,必须刷新页面重新获取数据才会更新。下面是具体的修复方案:

修复步骤:

  • 将传入的post props存入组件内部的state,让组件能手动更新数据
  • 监听post props的变化,确保外部数据更新时组件内的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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.06 01:50:20