在递增/递减时,如何确保计数器的状态对每个用户ID都是唯一的



我正在开发一个练习web应用程序,试图模仿Instagram的类似系统。

下面是我当前的代码——递增/递减是有效的,但它是以全局方式递增/递减的。

换句话说,如果我点击用户A的照片来增加它的赞数,那就可以了。

之后,如果我点击用户B的照片,它不会增加。相反,它颁布法令。

然后,如果我点击用户C的照片,它会增加

等等…

似乎所有用户都在共享点赞状态,这是不正确的

我希望喜欢/不喜欢的系统遵循Instagram的,但似乎无法完全确定。以下是实现这一切的所有代码。不确定我做错了什么。

Gallery.js:

const [isLikedClicked, setIsLikeClicked]                      = useState(false);
const [isDislikeClicked, setIsDislikeClicked]                 = useState(false);
const [userLikes, setUserLikes]                               = useState(null);
const [currentUserClicks, setCurrentUserClicks]               = useState(null);
const handleLikesBasedOnUserId = (likedPhotoUserId) => {
if(currentUserClicks >= 1) {
setCurrentUserClicks(currentUserClicks - 1);
setIsDislikeClicked(true);
handleDislike(likedPhotoUserId);
} else {
setCurrentUserClicks(currentUserClicks + 1);
setIsLikeClicked(true);
handleLike(likedPhotoUserId);
}
};
const handleLike = (likedPhotoUserId) => {
const url = 'http://127.0.0.1:8000/api/like';
const headers = {
"Accept": 'application/json',
"Authorization": `Bearer ${authToken}`
};
let data = {
'UserID': likedPhotoUserId
};
axios.post(url, data, {headers})
.then(resp => {
setUserLikes(resp.data.userLikes);
}).catch(err => {
console.log(err);
});
};
const handleDislike = (likedPhotoUserId) => {
const url = 'http://127.0.0.1:8000/api/dislike';
const headers = {
"Accept": 'application/json',
"Authorization": `Bearer ${authToken}`
};
let data = {
'UserID': likedPhotoUserId
};
axios.post(url, data, {headers})
.then(resp => {
setUserLikes(resp.data.userLikes);
}).catch(err => {
console.log(err);
});
};
return (
<>
<div className="main">
<ul className="cards">
{
gridData.map((photos) => {
return <Grid
likes={photos.likes}
src={photos.url}
currentUserClicks={currentUserClicks}
onClick={handleLikesBasedOnUserId}
isLikedClicked={isLikedClicked}
userId={photos.UserID}
/>
})
}
</ul>
</div>
</>
);

Grid.js:

const [likes, setLikes] = useState(props.likes);
const [likeValue, setLikeValue] = useState(null);
return (
<>
<li className="cards_item">
<div>
<div className="card_image">
<img src={props.src} alt="Photo" className="gallery-img" onClick={() => props.onClick(props.userId, props.isLikedClicked ? setLikeValue(props.user) : setLikes(props.likes + 1))}/>
</div>
<span style={{display: 'none'}}>{props.currentUserClicks}</span>
<h5 className="likes">Likes: {likes}</h5>
</div>
</li>
</>
);

后端控制器操作:

public function handleLike(Request $request)
{
try {
$userId                                  = $request->get('UserID');
Uploads::where(['UserID' => $userId])->update(['likes' => DB::raw('likes + 1')]);
$getUserLikes                            = $this->__usersRepository->getUserLikes($userId);
$userLikes                               = $getUserLikes[0]->likes;
return [
'UserID'                             => $userId,
'userLikes'                          => $userLikes,
];
} catch (Exception $e) {
Log::error($e->getMessage());
throw new Exception($e->getMessage(), $e->getCode(), $e);
}
}
public function handleDislike(Request $request)
{
try {
$userId                                  = $request->get('UserID');
Uploads::where(['UserID' => $userId])->update(['likes' => DB::raw('likes - 1')]);
$getUserLikes                            = $this->__usersRepository->getUserLikes($userId);
$userLikes                               = $getUserLikes[0]->likes;
return [
'UserID'                             => $userId,
'userLikes'                          => $userLikes
];
} catch (Exception $e) {
Log::error($e->getMessage());
throw new Exception($e->getMessage(), $e->getCode(), $e);
}
}

你似乎把点赞和照片联系在一起。UserId,所以对于这个答案的其余部分,我假设这是有效的,因为每个用户只有一张照片,而UserId实际上是一个照片id(比如说一张个人资料图片(。

您所描述的最初问题来自您的handleLikesBasedOnUserId函数。如果currentUserClicks为1,则将其设置为0;如果为0,则将设置为1。这就是为什么你每次点击都会交替点赞/不喜欢。

为了避免这种情况,需要进行一些结构重构。我将主要关注前端部分。

让我们来看看数据结构:有一个currentUserClicks变量相关吗?事实上没有。你根本不在乎用户总共点击了多少次。你想知道的是,对于每张照片,用户喜欢这张照片吗?

类似地,isLikedClickedisDislikedClickeduserLikes(根据我的理解,这是一张特定照片的点赞数?(只适用于一张照片,而你在网格上有多张照片。

知道了这一点,你应该考虑删除这些状态,并考虑userLikedPhotos,它应该是一个字典{[photoId:string]:boolean},甚至只是一组喜欢的照片ID。对于您的当前用户,这将是他喜欢的照片。它会提供你需要的所有信息,点击照片,如果照片ID在userLikedPhotos中,那么这意味着你正在执行一个不同的动作。如果它不在userLikedPhotos中(或者如果userLikes[photoId]===false(,那么您将执行类似的操作。

所以你的代码可能是这样的:

const [userLikedPhotos, setUserLikedPhotos] = useState({});  
const handleLikesBasedOnUserId = (likedPhotoUserId) => {
if(userLikedPhotos[likedPhotoUserId]) {
// unlike
delete userLikedPhotos[likePhotoUserId];
// optimistic UI update. Might get reverted if the backend call fails
gridData.find(photo => photo.userId === likedPhotoUserId).likes--;
// ignore backend for now
// handleDislike(likedPhotoUserId);
} else {
// like
userLikedPhotos[likePhotoUserId] = true;
// optimistic UI update. Might get reverted if the backend call fails
gridData.find(photo => photo.userId === likedPhotoUserId).likes++;
// ignore backend for now
// handleLike(likedPhotoUserId);
}
// we spread the userLikedPhotos to create a new object and force a rendering
setUserLikedPhotos({...userLikedPhotos});
};
return (
<>
<div className="main">
<ul className="cards">
{
gridData.map((photos) => {
return <Grid
likes={photos.likes}
src={photos.url}
onClick={handleLikesBasedOnUserId}
userId={photos.UserID}
isLikedByCurrentUser={!!userLikedPhotos[photos.UserId]}
/>
})
}
</ul>
</div>
</>
);

return (
<>
<li className="cards_item">
<div>
<div className="card_image">
<img src={props.src} alt="Photo" className="gallery-img" onClick={() => props.onClick(props.userId)}/>
</div>
<h5 className="likes">Likes: {props.likes}</h5>
</div>
</li>
</>
);

关于后端,我认为你不应该存储点赞数,而应该存储喜欢某张照片的用户列表,这个列表的长度就是点赞数。这样,如果用户刷新页面,你就可以检索到他已经喜欢的照片。

最新更新