1 回答
TA贡献1871条经验 获得超13个赞
您的主要问题是您直接改变状态而不是调用函数setState
。
为了清楚起见,我重命名data
为post
,因为您已经说过这是一个代表一篇文章数据的对象。
const [post, setPost] = useState(initialPost);
您不需要使用liked
as 状态,因为我们已经可以post
通过查看我们的用户是否在post.likes
数组中来从数据中访问此信息。这使我们拥有“单一的事实来源”,我们只需要在一个地方进行更新。
const isLiked = post.likes.some((like) => like.id === user.id);
我对likes
数组感到困惑。它看起来像是一组对象,它们只是{id: number}
,在这种情况下,您应该只拥有一组喜欢该帖子的用户的 ID。但也许对象中还有其他属性(如用户名或时间戳)。
在为像博客文章这样的复杂事物设计组件时,您希望分解出可以在应用程序的其他地方使用的小块。我们可以定义一个LikeButton
显示我们内心的。这是一个不处理任何逻辑的“演示”组件。它只需要知道是否发帖isLiked
以及要做什么onClick
。
export const LikeButton = ({ isLiked, onClick }) => {
const Icon = isLiked ? FavoriteRoundedIcon: FavoriteBorderRoundedIcon;
return (
<Icon
style={{ color: isLiked ? "red" : "gray" }}
onClick={onClick}
/>
);
};
我们关于喜欢和不喜欢的很多逻辑可能会被分解成某种usePostLike
钩子,但我还没有完全优化它,因为我不知道你的 API 在做什么以及我们应该如何响应我们得到的响应.
当用户单击赞按钮时,我们希望更改立即反映在 UI 中,因此我们调用setPost
并从数组中添加或删除当前用户likes
。我们必须用一个新对象设置状态,所以我们复制所有不随展开运算符改变的帖子属性...post
,然后likes
用编辑过的版本覆盖该属性。 filter()
并且concat()
都是返回数组新副本的安全数组函数。
我们还需要调用 API 来发布更改。您在“喜欢”和“不同”场景中使用相同的 url,因此我们可以调用广义函数并将方法名称或作为参数传递给对象,而不是调用axios.post
and 。我们可能可以以类似的方式组合我们的两个调用,并将and更改为一个函数。但就目前而言,这就是我所拥有的:axios.delete
axios.request
'post'
'delete'
config
setPost
likePost()
unlikePost()
toggleLikePost()
export const Post = ({ initialPost, user }) => {
const [post, setPost] = useState(initialPost);
const isLiked = post.likes.some((like) => like.id === user.id);
function likePost() {
console.log("liked the post");
// immediately update local state to reflect changes
setPost({
...post,
likes: post.likes.concat({ id: user.id })
});
// push changes to API
apiUpdateLike("post");
}
function unlikePost() {
console.log("unliked the post");
// immediately update local state to reflect changes
setPost({
...post,
likes: post.likes.filter((like) => like.id !== user.id)
});
// push changes to API
apiUpdateLike("delete");
}
// generalize like and unlike actions by passing method name 'post' or 'delete'
async function apiUpdateLike(method) {
try {
// send request to API
await axiosInstance.request("api/posts/" + post.slug + "/like/", { method });
// handle API response somehow, but not with window.location.reload()
} catch (e) {
console.log(e);
}
}
function onClickLike() {
if (isLiked) {
unlikePost();
} else {
likePost();
}
}
return (
<div>
<h2>{post.title}</h2>
<div>{post.likes.length} Likes</div>
<LikeButton onClick={onClickLike} isLiked={isLiked} />
</div>
);
};
添加回答
举报