按钮不会根据api调用在react js中改变状态

我有一个显示单个帖子的页面,我有一个喜欢按钮。如果帖子被点赞,当用户单击按钮时,它会将其状态更改为“不喜欢”按钮,但如果帖子不被点赞,则会注册“赞”并将 id 推送到数组中,但按钮状态没有更新,我必须重新加载页面才能看到该页面。有人可以告诉我如何解决这个问题吗?


这是代码:


    const [liked, setLiked] = useState(false)


    const [data, setData] = useState([]);


    function likePosts(post, user) {

        post.likes.push({ id: user });

        setData(post);

        axiosInstance.post('api/posts/' + post.slug + '/like/');

        window.location.reload()

    }


    function unlikePosts(post, user) {

        console.log('unliked the post');

        data.likes = data.likes.filter(x => x.id !== user);

        setData(data);

        return (

            axiosInstance.delete('api/posts/' + post.slug + '/like/')

        )

    }

对于按钮:


{data.likes && data.likes.find(x => x.id === user) ?

        (<FavoriteRoundedIcon style={{ color: "red" }}

            onClick={() => {

                unlikePosts(data, user)

                setLiked(() => liked === false)

            }   

        }

        />)

        : (<FavoriteBorderRoundedIcon

               onClick={() => {

               likePosts(data, user)

               setLiked(() => liked === true)

               }

        }

        />)

    }

谢谢,请询问是否需要更多详细信息。


Smart猫小萌
浏览 127回答 1
1回答

慕桂英4014372

您的主要问题是您直接改变状态而不是调用函数setState。为了清楚起见,我重命名data为post,因为您已经说过这是一个代表一篇文章数据的对象。const [post, setPost] = useState(initialPost);您不需要使用likedas 状态,因为我们已经可以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.postand 。我们可能可以以类似的方式组合我们的两个调用,并将and更改为一个函数。但就目前而言,这就是我所拥有的:axios.deleteaxios.request'post''delete'configsetPostlikePost()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>  );};
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

JavaScript