Home > database >  Updating 'Likes' on individual posts... ReactJS/Mern
Updating 'Likes' on individual posts... ReactJS/Mern

Time:09-15

A week ago, I posted a question on how to implement a "Like" feature for each individual post of my Mern stack CRUD app. I didn't receive any answers, but thanks to Reddit, a friendly experienced programmer helped me connect my ReactJS frontend, ExpressJS backend, and MongoDB all together for it to work beautifully.

Problem now is, although I can save Likes from my ReactJS frontend into my MongoDB...the dynamic display of my Like counts on the frontend is still having issues. If I create two posts, and press the Like button on one post, it turns all the Like counts on every post back to 0—except the post that i'm clicking the Like button on. When I hit refresh, all the likeCounts from my backend come back fine--but all get turned to 0 once again--when I click a Like button on an individual post...My code below....

import React, {useState} from 'react'
import Axios  from 'axios';
import Space from './images/space.jpg'

function ExperienceLikes({setListExperience, listExperience, picClicked}) {
    let initLikes = new Array(listExperience.length).fill(0)
    const [likes, setLikes] = useState(initLikes)
    const [liked, setLiked] = useState(false)

    console.log(initLikes)

    const cardStyles = {
        background: "#ffffff",
        display: "flex",
        flexDirection: "column",
        justifyContent: "center",
        width: "161px",
        height: "180px",
        marginLeft: "30px",
        marginRight: "30px",
        marginTop: "20px",
        position: "relative",
    }

    const updateLike = (id, x) => {
        let tempLikes = initLikes;
        Axios.put(`http://localhost:9001/${id}/likePost`)
            .then((response) => {
                    setListExperience((previous) => {
                        return previous.map((hmm) => {
                            return hmm.id === id ? id : hmm
                        })
                    })
                    setLiked(true)
                    tempLikes[x] = tempLikes[x]   response.data.likeCount
                    setLikes(tempLikes)
                    
                }
            )
    }

    const deletePost = (id) => {
        Axios.delete(`http://localhost:9001/${id}/delete`)
            .then(() => {
                setListExperience(listExperience.filter((idx) => {
                    return idx._id != id
                }))
            })
    }

    return(
        <>
        {listExperience.map((x, id) => 
                    <div key={x._id} className={`experience--card$`} style={cardStyles}>
                        <div className='locate'>
                            {x.location}
                        </div>
                        <div className='image' style={ { display: "flex", justifyContent: "center"} } >
                                <img src={Space} alt='pic' style={ { maxWidth: "100%", maxHeight:"100%", overflow: "hidden", marginBottom: "20px"} } height={125} />
                        </div> 
                        
                        <div className={picClicked === true ?'likeBtnContainer-hidden' : 'likeBtnContainer'}>
                            <button className='likeBtn' type='button' onClick={() => updateLike(x._id, id)}>Like {liked == true ? likes[id] : x.likeCount}</button>
                        </div>
                        <div className='deleteBtnContainer'>
                            <button className='deleteBtn' type='button' onClick={() => deletePost(x._id)}>Delete</button>
                        </div>
                    </div>
            )}
        </>
    )
}

export default ExperienceLikes

In the code above, the problem I feel like i'm having is maybe something to do with my [Liked, setLiked] boolean. But I just don't know how to correct it. What do I have to do so that Likes only increment on one post, while the likeCounts remain the same on the other posts?

Below, is the code to my other component where my posts are getting created...

import React, { useState, useEffect} from 'react';
import './Experiences.css'
import Axios from 'axios';
import ExperienceLikes from './ExperienceLikes';

function Experiences() {
    const [listExperience, setListExperience] = useState([]);
    const [location, setLocation] = useState("")
    const [picClicked, setPickClicked] = useState(false)
    const [viewLocation, setViewLocation] = ("")

    const createExperience = (e) => {
        e.preventDefault();

        Axios.post('http://localhost:9001/', {location})
            .then((response) => {
                setListExperience([...listExperience,{_id: response.data._id, location, likeCount: response.data.likeCount}]);
            })  
    }    

    useEffect(() => {
        Axios.get('http://localhost:9001/')
            .then((response) => {
                setListExperience(response.data)
            })
    }, []);

return (
    <>
    <div className='form--contain'>
        <div className='form--card'>
            <form onSubmit={createExperience}>
                <textarea type='text' onChange={(event) => {setLocation(event.target.value)}} />
                <button type='submit'>Submit</button>
            </form>
        </div>
    </div>    
        <div className='experience--container'>
            <ExperienceLikes setListExperience={setListExperience} picClicked={picClicked} listExperience={listExperience} />
        </div>
    </>
)
}

export default Experiences

CodePudding user response:

You don't need [Liked, setLiked] state. You can just update the listExperience state when the user press the like button.

CodePudding user response:

You can achieve your goal with less code than you expect.

You have listExperience array. Each item in this array has a likeCount property afaics. Correct? Now, you are using .map to render your items from this array.

Now, lets take a look at the updateLike method. You made it accept the id of the item and the index of this item in the array, which you named id and in the function you called it x. Tt is a bad naming, to be honest, a bit idx will match better. Now, what you need to do - is to make this method to accept the (item), your x.

So make it looks like this:

const updateLike = (experience) => {
  Axios.put(`http://localhost:9001/${experience._id}/likePost`).then(
    (response) => {
      // Based on your code I assume that response.data really returns likeCount
      // So just update the passed item's likeCount
      experience.likeCount = response.data.likeCount;

      // Question about where and how you are storing the data about if the item is liked
      // check for if null or undefined
      experience.isLiked =
        experience.isLiked == null ? true : !experience.isLiked;

      // We mutated the item from the array, now we need to update the reference
      // of this array so React will detect changes.
      setListExperience((current) => [...current]);
    }
  );
};

And now update your <button /> a bit

<button
  className="likeBtn"
  type="button"
  onClick={() => updateLike(x)}
>
  {/* I have no idea what was the idea of this line below */}
  Like {liked == true ? likes[id] : x.likeCount}
</button>
  • Related