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>
? );
};
添加回答
舉報