为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

Smart猫小萌 2023-06-09 15:12:56
我有一个显示单个帖子的页面,我有一个喜欢按钮。如果帖子被点赞,当用户单击按钮时,它会将其状态更改为“不喜欢”按钮,但如果帖子不被点赞,则会注册“赞”并将 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)               }        }        />)    }谢谢,请询问是否需要更多详细信息。
查看完整描述

1 回答

?
慕桂英4014372

TA贡献1871条经验 获得超13个赞

您的主要问题是您直接改变状态而不是调用函数setState

为了清楚起见,我重命名datapost,因为您已经说过这是一个代表一篇文章数据的对象。

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>

  );

};


查看完整回答
反对 回复 2023-06-09
  • 1 回答
  • 0 关注
  • 126 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信