'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 |
