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

如何在点赞数变化时实时渲染点赞按钮的计数?

问题描述

我已创建一个点赞按钮,点击后会将事件发送至后端以更新帖子,后端会返回更新后的帖子,但我无法渲染更新后的帖子。

帖子加载完成后会作为参数传入该页面

PostCard组件代码

import React, { Fragment, useEffect, useState } from 'react';
import "./PostCard.css";
import Person4Icon from '@mui/icons-material/Person4';
import FavoriteIcon from '@mui/icons-material/Favorite';
import HeartBrokenIcon from '@mui/icons-material/HeartBroken';
import ForumOutlinedIcon from '@mui/icons-material/ForumOutlined';
import { Link } from 'react-router-dom';
import { likeDislike } from '../../actions/postAction';
import { useSelector, useDispatch } from "react-redux";

const PostCard = ({post}) => {
    // console.log(post);
    const dispatch = useDispatch();
    const { like } = useSelector((state) => state.likePost);
   
    
    const { isAuthenticated, user } = useSelector((state) => state.user);
    const [likeCount, setLikeCount] = useState(Object.keys(post.hearts).length);
    var isLiked=false;
    if(isAuthenticated){
        isLiked = Boolean(post.hearts[user._id]);
    }
    
    

    const likes = () => {
        dispatch(likeDislike(post._id));
        setLikeCount(Object.keys(post.hearts).length);
        console.log(like.hearts);
        console.log(Object.keys(like.hearts).length);
    }

   

    const dislikes = () => {
        dispatch(likeDislike(post._id))
    }

  return (
    <Fragment>
        
        <div className='card'>
            <div className='profile_icon'><Person4Icon 
            style={{color: post.avatarColor}}
            /></div>
            <div className='post'>
            <Link className='card_head' to={`/comment/${post._id}`}>
                <h4 
                style={{color:"orange"}}
                >{post.userName}</h4>
                <p>{post.post}</p>
            </Link>
                <div className='post_footer'>
                <Link className='card_head' to={`/comment/${post._id}`}>
                    <div className='post_footer_button'>
                        <ForumOutlinedIcon/>
                        <span className='number'>{post.comments.length}</span>
                    </div>
                </Link>
                    <div className='post_footer_button'>
                        <HeartBrokenIcon onClick={dislikes}/>
                        <span className='number'>{post.condolences.length}</span>
                    </div>
                    <div className='post_footer_button'>
                        <FavoriteIcon onClick={likes}/>
                        <span className='number'>{likeCount}</span>
                    </div>
                </div>
            </div>
        </div>
        <div className='break'>
            
        </div>
        
    </Fragment>
  )
}

export default PostCard

点赞事件的Dispatch Action部分

//Likes Dislikes
export const likeDislike = (id) => async (dispatch) => {
    try {
        dispatch({ type: LIKE_POST_REQUEST });

        const config = { headers: { "Content-Type": "application/json" } };
    
        const { data } = await axios.put(`/social/like`, {id}, config);
        
        console.log(data);
    
        dispatch({
          type: LIKE_POST_SUCCESS,
          payload: data.updatedPost,
        });
      } catch (error) {
        dispatch({
          type: LIKE_POST_FAIL,
          payload: error.response.data.message,
        });
      }
}

更新点赞帖子的Reducer

export const likePostReducer = (state = {like: {}}, action) => {
  switch (action.type) {
    case LIKE_POST_REQUEST:
      return {
        ...state,
        loading: true,
      };
    case LIKE_POST_SUCCESS:
      return {
        loading: false,
        like: action.payload,
      };
    case LIKE_POST_FAIL:
      return {
        loading: false,
        error: action.payload,
      };
    case CLEAR_ERRORS:
      return {
        ...state,
        error: null,
      };
    default:
      return state;
  }
};

后端更新帖子的代码

exports.likePost = catchAsyncErrors(async(req,res,next) => {

    // console.log(req.body);
    const {id} = req.body;
    const post = await Post.findById(id);
    const user = await User.findById(req.user._id); 
    const isLiked = post.hearts.get(user._id);

    if (isLiked) {
        post.hearts.delete(user._id);
    } else {
        post.hearts.set(user._id, true);
    }
    const updatedPost = await Post.findByIdAndUpdate(
        id,
        { hearts: post.hearts },
        { new: true }
    );
                 
    res.status(200).json({
        success:true,
        updatedPost,
    });

});

PostCard的父组件(Home组件)

import React, { Fragment, useEffect } from 'react';
import "./Home.css";
import PostCard from '../Layout/PostCard';
import CreatePost from '../Layout/CreatePost';
import { getPosts, clearErrors } from '../../actions/postAction';
import { useSelector, useDispatch } from "react-redux";
import {toast} from "react-toastify";
import Loader from "../Loader/Loader";
import { CREATE_POST_RESET } from '../../constants/postConstants';
import AddIcon from '@mui/icons-material/Add';
import { useNavigate } from "react-router-dom";

const Home = () => {

 const dispatch = useDispatch();
 const navigate = useNavigate();
 const { loading, error, posts } = useSelector((state) => state.posts);
 const { success } = useSelector((state) => state.createPost);
 const { isAuthenticated } = useSelector((state) => state.user);
 // console.log(user);

 const open = () => {
   if(isAuthenticated===false){
     toast.error("Login first");
   }

   if(isAuthenticated){
     navigate("/createPost");
   }
 }
 
 useEffect(() => {
   if(error){
     toast.error(error);
     dispatch(clearErrors());
   }
   if (success) {
     toast.success("Posted");
     dispatch({ type: CREATE_POST_RESET });
   }
   dispatch(getPosts());
 },[dispatch, success, error]);
 
 return (
   <Fragment>
       {loading ? (
         <Loader/>
       ) : (
         <Fragment>
           <div className='home'>
             <div className='home_left'>
                 <div className='home_heading'>
                   <h4>Try something here</h4>
                 </div>
                 <div>
                   {posts &&
                     posts.map((post) => {
                       return(
                         <PostCard key={post._id} post={post} />
                       );
                     })}
                 </div>
             </div>
             <div className='home_right'>
                 <CreatePost/>
             </div>
           </div>

           {/* FLOATING BUTTON */}
           <div className='floating_button'>
               <button onClick={open}>
                   <AddIcon/>
               </button>
           </div>
         </Fragment>
       )}
   </Fragment>
 )
}

export default Home;

内容的提问来源于stack exchange,提问作者Atulya Jaiswal

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.07 03:01:11