I'm trying to implement the same like/dislike functionality as Instagram on the frontend.
The setGridData
hook is grabbing the correct values from the server and handleDislike()
and handleLike()
are correctly updating the DB table for the currently logged in user so no issues there.
The problem I'm having is implementing a way the currently logged in user will hit the if
(dislike) block or the else
(like) block in handleLikesBasedOnUserId()
based on the is_liked
boolean value.
In the JSX, I'm correctly displaying Like
or Dislike
on the button based on the is_liked
boolean value that's coming from the gridData
hook for the currently logged in user. However, when clicking the button, it's always hitting the else
(like) block in handleLikesBasedOnUserId()
no matter what.
How can I fix it so that it behaves exactly the same as Instagram?
Here's the code:
const Grid = () => {
let authToken = localStorage.getItem('token');
const [gridData, setGridData] = useState([]);
const [userLikedPhotos, setUserLikedPhotos] = useState({});
useEffect(() => {
const headers = {
"Accept": 'application/json',
"Authorization": `Bearer ${authToken}`
};
axios.get('http://127.0.0.1:8000/api/get-user-uploads-data', {headers})
.then(resp => {
console.log(resp.data);
setGridData(resp.data);
}).catch(err => {
console.log(err);
});
}, []);
const handleLikesBasedOnUserId = (likedPhotoUserId, userName, likedPhotoId, is_liked) => {
if(userLikedPhotos[likedPhotoUserId]) {
// dislike
delete userLikedPhotos[likedPhotoUserId];
gridData.find(photo => photo.UserID === likedPhotoUserId && photo.is_liked === is_liked && photo.photo_id === likedPhotoId).likes--;
handleDislike(likedPhotoUserId, userName, likedPhotoId);
console.log("Disliked");
} else {
// like
userLikedPhotos[likedPhotoUserId] = true;
gridData.find(photo => photo.UserID === likedPhotoUserId && photo.is_liked === is_liked && photo.photo_id === likedPhotoId).likes ;
handleLike(likedPhotoUserId, userName, likedPhotoId);
console.log("Liked");
}
setUserLikedPhotos({...userLikedPhotos});
};
return (
<>
<div className="img-container">
{
gridData.map((photos, index) => {
return (
<>
<div className="userDetails">
<span className="likesAmt">❤️ {photos.likes}</span>
<Button
variant={photos.is_liked ? `danger` : 'success'}
onClick={() => handleLikesBasedOnUserId(photos.UserID, photos.name, photos.photo_id, photos.is_liked)}
>
{photos.is_liked ? `Dislike` : 'Like'}
</Button>
</div>
</>
)
})
}
</div>
</>
)
}
export default Grid;
CodePudding user response:
The moment you set state for setUserLikedPhotos, your component re-renders and it sets your state to default. Please try to use useRef().
let existingLikedPhotos = useRef({});
const [userLikedPhotos, setUserLikedPhotos] = useState(existingLikedPhotos.current);
.
.
.
existingLikedPhotos.current = {...userLikedPhotos};
setUserLikedPhotos({...userLikedPhotos});
Make the changes as suggested. Then from next time it rerenders it will have your changes from previous rerenders in useRef variable.
CodePudding user response:
Do not modify state variable. Instead copy it first, then modify the copy:
const handleLikesBasedOnUserId = (likedPhotoUserId, userName, likedPhotoId, is_liked) => { const temp = {...userLikedPhotos}; if(temp[likedPhotoUserId]) { // dislike delete temp[likedPhotoUserId]; gridData.find(photo => photo.UserID === likedPhotoUserId && photo.is_liked === is_liked && photo.photo_id === likedPhotoId).likes--; handleDislike(likedPhotoUserId, userName, likedPhotoId); console.log("Disliked"); } else { // like temp[likedPhotoUserId] = true; gridData.find(photo => photo.UserID === likedPhotoUserId && photo.is_liked === is_liked && photo.photo_id === likedPhotoId).likes ; handleLike(likedPhotoUserId, userName, likedPhotoId); console.log("Liked"); } setUserLikedPhotos({...temp}); };
Don't you need to initialize
userLikedPhotos
to theid
s of the photos havingphotos.is_liked === true
at the beginning?Why do you need
userLikedPhotos
anyway? Why not just usephoto.is_liked
?
CodePudding user response:
The toggle() method toggles between hide() and show() for the selected elements. This method checks the selected elements for visibility. show() is run if an element is hidden. hide() is run if an element is visible - This creates a toggle effect.