'How do I change the increment/decrement number based on response data?

The backend calls to increment likes depicted by handleLike() and handleLike() functions successfully return the response of containing the number that's been incremented/decremented.

Unfortunately, this is the only way I can see photos.likes incremented/decrement in real time.

My question is: How do I make it so that I able to only increment/decrement the likes amount by 1 for the specific image's UserID that's being clicked on instead of ALL of them. Also, is there a way to avoid using frontend logic to accomplish this since the increment/decrement is happening on the server side?

I've hit a wall on this and not sure how to overcome it.

const [currentUserClicks, setCurrentUserClicks]               = useState(1);
const [onChangeLikes, setonChangeLikes]                       = useState(null);

const handleLikesBasedOnUserId = (likedPhotoUserId) => {
        if(currentUserClicks > 1) {
            setCurrentUserClicks(currentUserClicks - 1);
            handleDisLike(likedPhotoUserId); // sends data to server to decrement DB column
            setonChangeLikes(false);
        } else {
            setCurrentUserClicks(currentUserClicks + 1); 
            handleLike(likedPhotoUserId); // sends data to server to increment DB column
            setonChangeLikes(true);
        }
    };


return(
{
 data.map((photos, index) => {
   return <>
     <div key={index}>
       <img src={photos.url} alt="Photo" className="gallery-img" onClick={() => handleLikesBasedOnUserId(photos.UserID)}/>
       <h5 className="likes">Likes: {!onChangeLikes ? photos.likes - 1: photos.likes + 1}</h5>      
     </div>
   </>
  })
}
);


Solution 1:[1]

In these cases you need to move the state locally to the mapped elements:

const { useState, useEffect } = React;

const App = () => data.map((pic) => <Pic key={pic.id} data={pic} />);

const Pic = ({ data }) => {
  const [likes, setLikes] = useState(data.likes);

  const handleClick = (type) => {
    if (type === 'increment') {
      if (likes - data.likes <= 0) {
        // handleLike(id); // sends data to server to increment DB column
        setLikes((l) => l + 1);
      } else {
        // handleDisLike(id); // sends data to server to decrement DB column
        setLikes((l) => l - 1);
      }
    }
    if (type === 'decrement') {
      if (likes - data.likes >= 0) {
        // handleDisLike(id); // sends data to server to decrement DB column
        setLikes((l) => l - 1);
      } else {
        // handleLike(id); // sends data to server to increment DB column
        setLikes((l) => l + 1);
      }
    }
  };

  return (
    <div>
      <img src={data.url} alt="Photo" className="gallery-img" />
      <div className="container">
        <h5 onClick={() => handleClick('decrement')}>-</h5>
        <h5 className="likes">
          Likes:
          {likes}
        </h5>
        <h5 onClick={() => handleClick('increment')}>+</h5>
      </div>
    </div>
  );
};


const data = [
  {
    url: 'https://upload.wikimedia.org/wikipedia/commons/a/a6/Pink_lady_and_cross_section.jpg',
    likes: 10,
    id: 'apple1',
  },
  {
    url: 'https://upload.wikimedia.org/wikipedia/commons/2/22/Malus_domestica_a1.jpg',
    likes: 25,
    id: 'apple2',
  },
];

const root = ReactDOM.createRoot(document.getElementById("root"))
root.render(<App/>)
.gallery-img {
  width: 100px;
}

.container {
  display: flex;
}

h5 {
  cursor: pointer;
  margin: 10px;
}
<div id="root"></div>
<script crossorigin src="https://unpkg.com/react@18/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>

I was not sure what you were trying to do since you did not have any like/dislike button, so I was not sure of your logic: (first click --> like | second click --> reset | third click ?) So I added two like/dislike clickables and tweaked a bit the logic to permit only one like/dislike vote, and reset if trying to increase/decrease further, as it works here on StackOverflow.

Consider that you should handle this logic serverside by the way, and you should make a call on component mount to check if the user has already voted or not, in a real world scenario, or it's enough a refresh to be able to vote multiple times.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Cesare Polonara