0

我正在做一个 facebook 克隆,每次我按赞按钮时,我都想立即看到更改,这是 swr 提供的,但是,它只会在 4-8 秒后更新:/

我试图做的是:当我点击喜欢的按钮时,我首先改变 swr 提供的缓存,然后我调用 API,然后重新验证数据以查看数据是否正确,实际上我控制台日志缓存并立即更新,但 UI 没有,我不知道为什么

让我给我的代码一些上下文

这就是我的出版物的样子(在 pub 里面是 likes 属性)


export type theLikes = {
  identifier: string;
};

export type theComment = {
  _id?: string;
  body: string;
  name: string;
  perfil?: string;
  identifier: string;
  createdAt: string;
  likesComments?: theLikes[];
};

export interface Ipublication {
  _id?: string;
  body: string;

  photo: string;

  creator: {
    name: string;
    perfil?: string;
    identifier: string;
  };

  likes?: theLikes[];

  comments?: theComment[];

  createdAt: string;
}

export type thePublication = {
  data: Ipublication[];
};

这是我要求所有带有 getStaticProps 的出版物的地方

const PublicationsHome = ({ data: allPubs }) => {
  // All pubs

  const { data: Publications }: thePublication = useSWR(
    `${process.env.URL}/api/publication`,
    {
      initialData: allPubs,
      revalidateOnFocus: false
    }
  );


  return (
    <>
      {Publications ? (
        <>
          <PublicationsHomeHero>
            {/* Create pub */}
            <CreatePubs />
            {/* Show pub */}
            {Publications.map(publication => {
              return <Pubs key={publication._id} publication={publication} />;
            })}
          </PublicationsHomeHero>
        </>
      ) : (
        <div></div>
      )}
    </>
  );
};

export const getStaticProps: GetStaticProps = async () => {
  const { data } = await axios.get(`${process.env.URL}/api/publication`);

  return {
    props: data
  };
};

export default PublicationsHome;

这就是like按钮所在的地方(关注LikePub,那里有逻辑)

条件很简单,如果用户已经喜欢了一个酒吧,就砍掉喜欢,否则,喜欢这个酒吧


interface IlikesCommentsProps {
  publication: Ipublication;
}

const LikesComments: React.FC<IlikesCommentsProps> = ({ publication }) => {

const LikePub = async (): Promise<void> => {
    try {
      if (publication.likes.find(f => f.identifier === userAuth.user.id)) {
        mutate(
          `${process.env.URL}/api/publication`,
          (allPublications: Ipublication[]) => {
            const currentPub = allPublications.find(f => f === publication);

            const deleteLike = currentPub.likes.findIndex(
              f => f.identifier === userAuth.user.id
            );

            currentPub.likes.splice(deleteLike, 1);

            const updatePub = allPublications.map(pub =>
              pub._id === currentPub._id ? currentPub : pub
            );

            return updatePub;
          },
          false
        );
      } else {
        mutate(
          `${process.env.URL}/api/publication`,
          (allPublications: Ipublication[]) => {
            const currentPub = allPublications.find(f => f === publication);
            currentPub.likes.push({ identifier: userAuth.user.id });

            const updatePub = allPublications.map(pub =>
              pub._id === currentPub._id ? currentPub : pub
            );

            return updatePub;
          },
          false
        );
      }
      console.log(publication.likes);
      await like({ identifier: userAuth.user.id }, publication._id);
      mutate(`${process.env.URL}/api/publication`);
    } catch (err) {
      if (err) {
        mutate(`${process.env.URL}/api/publication`);
      }
    }
  };

return (

      <motion.div
          onClick={LikePub}
          variants={Actions}
          whileHover="whileHover"
          whileTap="whileTap"
        >
              <motion.span>
                <LikeIcon colorIcon="rgb(32, 120, 244)" />
              </motion.span>
              <LikeCommentText
                separation="0.2rem"
                colorText="rgb(32, 120, 244)"
              >
                Me gusta
              </LikeCommentText>
        </motion.div>

)
}

正如你所看到的,我 console.log 发布的喜欢,这就是发生的事情

在此处输入图像描述

标识符被添加到缓存中,表示用户喜欢该 pub,但 UI 没有更新,更新需要 4 - 7 秒,可能更长时间,删除like 时发生同样的事情,看看这个

在此处输入图像描述

剪切之类的,但是,用户界面不更新

我很绝望,我已经尝试了一切,我已经尝试解决这个问题将近一个星期,但什么也没找到,我做错了什么,这是一个错误吗?

4

1 回答 1

1

我相信问题是你直接改变了(在 javascript 中不是 swr 意义上的)swr 对 swr 完全不可见的数据。只有从 API 返回响应时,您的状态才会更新并最终触发 swr 的观察者。


在这里,您可能会注意到这currentPub.likes是对象内部的一个数组(引用)currentPub。您直接对其进行变异(使用splice),然后将相同的引用插入回allPublications对象中。从 swr 的角度来看,likes阵列没有改变。它仍然拥有与突变之前相同的引用:

(allPublications: Ipublication[]) => {
    const currentPub = allPublications.find(f => f === publication);

    const deleteLike = currentPub.likes.findIndex(
        f => f.identifier === userAuth.user.id
    );

    currentPub.likes.splice(deleteLike, 1);
    const updatePub = allPublications.map(pub =>
        pub._id === currentPub._id ? currentPub : pub
    );

    return updatePub;
}

用于说明行为的片段:

const allPublications = [{ attr: 'attr', likes: [1, 2, 3] }]
const currentPub = allPublications[0]
currentPub.likes.splice(1, 1)
const updatePub = allPublications.map((pub, idx) => idx === 0 ? currentPub :  pub)

console.log(updatePub[0] === allPublications[0]) // true
console.log(updatePub[0].likes === allPublications[0].likes) // true. the reference stays the same
console.log(updatePub[0]) // while the object has changed

您应该重写它以排除直接突变,并始终为更改的对象/数组返回更改的引用。就像是:

(allPublications: Ipublication[]) => {
    const currentPub = allPublications.find(f => f === publication);

    const likes = currentPub.likes.filter( // filter creates new array (reference)
        f => f.identifier !== userAuth.user.id
    );
    const updatePub = allPublications.map(pub => // map creates new array
        pub._id === currentPub._id ? { ...currentPub, likes } : pub // {} creates new object (reference)
    );

    return updatePub;
}

const allPublications = [{ attr: 'attr', likes: [1, 2, 3] }]
const currentPub = allPublications[0]

const likes = currentPub.likes.filter((el) => el !== 2)
const updatePub = allPublications.map((pub, idx) => 
  idx === 0 ? { ...currentPub, likes } :  pub
)

console.log(updatePub[0] === allPublications[0]) // false
console.log(updatePub[0].likes === allPublications[0].likes) // false
console.log(updatePub[0])

else并对分支变异函数做同样的事情。

于 2021-06-07T18:32:55.997 回答