Swr 的缓存更新,但 UI 不会无缘无故地更新 - swr hook Next.js(使用打字稿)

Swr's cache updates but UI doesn't for no reason - swr hook Next.js ( with typescript )

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

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

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

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


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;

点赞按钮在这里(关注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 发布的喜欢,这就是发生的事情

标识符被添加到缓存中,意味着用户喜欢该酒吧,但 UI 没有更新,更新需要 4 - 7 秒,可能更多,同样的事情发生在去掉类似的,看这个

剪掉了,但是,UI没有更新

我很绝望,我已经尝试了所有方法,我已经尝试修复这个问题将近一个星期了,但什么也没发现,我做错了什么,这是一个错误吗?

我认为问题在于您正在直接变异(在 javascript 而非 swr 意义上)swr 完全不可见的 swr 数据。只有当 return 从 API 得到响应时,你的状态才会更新,最终触发 swr 的观察者。


在这里您可能会注意到 currentPub.likescurrentPub 对象中的一个数组(引用)。您直接对其进行变异(使用 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

您应该重写它以排除直接突变,并且总是 return 更改引用以更改 objects/arrays。类似于:

(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 分支变异函数执行相同的操作。