首页 > 解决方案 > Array.includes 在反应组件加载时返回冲突结果

问题描述

我有一个Profile组件,它在加载时调用 Django 服务器来获取一组表示已添加书签的配置文件的 ID。如果书签数组包含用户正在使用的配置文件的 ID(即,如果用户正在使用/profile/1 并且 if [1, 4, 6].includes(1)),则应填写页面上的 img,否则应仅概述。用户可以单击 img,然后调用后端将该 ID 添加到数组中。再次单击它会将其从阵列中删除。

但是,由于一些我不明白的渲染顺序,img 没有正确切换到填充版本。 截屏 在这里,您可以看到组件的 devtools 信息InfoCard,它是Profile. 您还可以看到配置文件 1 在bookmarks我传入的数组 prop 中InfoCard,这isFavourite也是正确的。是我在父级中执行isFavourite的方法的结果, . 但是 img(名称旁边的粉红色书签轮廓)未填充。您还可以看到我在登录之前登录了三次。该控制台日志采用:的方法。includes()Profilefalsetruerender()InfoCardconsole.log(this.props.isFavourite);

这是我编写所有这些的方式:

Profile.js

  const [bookmarks, setBookmarks] = useState([]);
  const [isFavourite, setIsFavourite] = useState(false);

  const isUser = checkUser(
    localStorage.getItem("CONNECTORY_userId"),
    match.params.userId
  );

  const changeId = parseInt(localStorage.getItem("CONNECTORY_changeId"));

  useEffect(() => {
    async function fetchBookmarks() {
      const bookmarksData = await fetch(
        `${config.url}/profile/favouriteProfiles/${changeId}`
      ).then((res) => res.json());
      const reducedBookmarksData = bookmarksData.map(({ id }) => id);
      setBookmarks(reducedBookmarksData);
      const isFavouriteCheck =
        reducedBookmarksData.length > 0
          ? reducedBookmarksData.includes(parseInt(match.params.userId, 10))
          : false;
      setIsFavourite(isFavouriteCheck);
    }
    fetchBookmarks();
  }, [match.params.userId, history, changeId, isFavourite]);

  const handleChildBookmarkClick = async (id) => {
    await fetch(`${config.url}/user/favourites/${changeId}/${id}`);
  };

  return (
    <>
        {profileData && (
          <InfoCard
            data={profileData}
            experienceData={
              profileData.experience ? profileData.experience[0] : null
            }
            isUser={isUser}
            isFavourite={isFavourite}
            bookmarks={bookmarks}
            handleBookmarkClick={handleChildBookmarkClick}
          />
        )}
    </>
  );

InfoCard.js

export default class InfoCard extends Component {
  constructor(props) {
    super(props);
    this.state = {
      favourite: this.props.isFavourite,
    };
  }

  componentDidMount = () => {
    this.setState({ favourite: this.props.isFavourite });
  };

  handleBookmarkClick = () => {
    if (this.props.isUser) {
      return;
    }
    this.props.handleBookmarkClick(this.props.data.id);
    this.setState((prevState) => ({ favourite: !prevState.favourite }));
  };

  render() {
    console.log(this.props.isFavourite);
  ...
  {!this.props.isUser && (
     <button
       className="bookmark-container"
       onClick={this.handleBookmarkClick}
     >
       <img
         className="info-card-bookmark"
         src={this.state.favourite ? bookmarkFull : bookmarkEmpty}
         alt="Add this profile to your bookmarks"
       />
     </button>
   )}
  ...

我是否以正确的顺序渲染事物?我认为它也可能与异步函数有关,我也有点弱。

标签: javascriptarraysreactjsreact-lifecycle

解决方案


下面的代码:

const handleChildBookmarkClick = async (id) => {
 await fetch(`${config.url}/user/favourites/${changeId}/${id}`);
};

请求成功时什么都不做。如果我理解正确,它应该调用setIsFavourite或以某种方式触发fetchBookmarks,以便 Profile 重新获取数据并更新状态(这似乎有点矫枉过正)。

下面的代码看起来也很可疑:

componentDidMount = () => {
 this.setState({ favourite: this.props.isFavourite });
};

您应该直接使用道具 likethis.props.isFavourite或使用getDerivedStateFromProps. 将 props 克隆到 state 通常不是一个好主意,因为它断开了父子关系并复制了 state。
例如,在这种情况下,您最终没有更新isFavouriteProfile 的状态。isFavourite应该只存在于一个地方。


推荐阅读