Home > Enterprise >  How can I implement toggling based on data received from endpoint?
How can I implement toggling based on data received from endpoint?

Time:12-18

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:

  1. 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});
    };
    
  2. Don't you need to initialize userLikedPhotos to the ids of the photos having photos.is_liked === true at the beginning?

  3. Why do you need userLikedPhotos anyway? Why not just use photo.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.

  • Related