Diego
Diego

Reputation: 681

Trigger cache to make sure data is right problem - swr hook - next.js ( with typescript )

In my next.js app i'm using the swr hook since it provides cache and real time updates, and that is quite great for my project ( facebook clone ), but, there's a problem.

The problem, is that, in my publications, i fetch them along with getStaticProps, and i just map the array and everything great, but, when i do an action, like, liking a post, or commenting a post, i mutate the cache, and i thought that what that does, is to ask the server if the information that is in the cache is right.

But, what it really does, is that, it makes another API call, and, the problem with that, is that, if i like a publication, after the call to the API to make sure everything is right in the cache, if there are 30 new publications, they will appear in the screen, and i don't want that, i want the pubs the user on screen requested at the beggining, imagine comenting on a post, then there are 50 new post so you lost the post where you commented...

Let me show you a litle bit of my code.

First, let me show you my posts interfaces

// Publication representation

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[];
};

This is where i'm making the call to get all posts

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

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


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

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

  return {
    props: data
  };
};

export default PublicationsHome;

And, for example, this is how i create a comment, i update cache, make the call to the API, then mutate to see if data is right

  // Create comment

  const handleSubmit = async (e: FormEvent<HTMLFormElement>): Promise<void> => {
    e.preventDefault();

    try {

      mutate(
        `${process.env.URL}/api/publication`,
        (allPubs: Ipublication[]) => {
          const currentPub = allPubs.find(f => f === publication);

          const updatePub = allPubs.map(pub =>
            pub._id === currentPub._id
              ? {
                  ...currentPub,
                  comments: [
                    {
                      body: commentBody,
                      createdAt: new Date().toISOString(),
                      identifier: userAuth.user.id,
                      name: userAuth.user.name
                    },
                    ...currentPub.comments
                  ]
                }
              : pub
          );

          return updatePub;
        },
        false
      );
      await createComment(
        { identifier: userAuth.user.id, body: commentBody },
        publication._id
      );
      mutate(`${process.env.URL}/api/publication`);

    } catch (err) {
      mutate(`${process.env.URL}/api/publication`);
    }
  };

Now, after creating the comment, as i already mentioned, it makes another call to the API, and if there are new posts or whatever, it will appear in the screen, and i just want to keep the posts i have or add new ones if i'm the one that created them.

So, let's say that i will like a post

enter image description here

Everything is great and fast, but, after making sure data is right, another post will appear because another user created it

enter image description here

Is there a way to make sure data is right without making another call to the API that will add more posts to the screen ?

I'm new to this swr hook, so, hope you can help me and thanks for your time !

Upate

There's a way to update cache without needing to refetch

many POST APIs will just return the updated data directly, so we don’t need to revalidate again. Here’s an example showing the “local mutate - request - update” usage:

mutate('/api/user', newUser, false)      // use `false` to mutate without revalidation
mutate('/api/user', updateUser(newUser)) // `updateUser` is a Promise of the request,
                                         // which returns the updated document

But, i don't kwow how should i change my code to implement this, any ideas !?

Upvotes: 2

Views: 1082

Answers (1)

Diego
Diego

Reputation: 681

If you want to update the cache, and make sure everything is right, withouth having to make another call to the API, this seems like working

Change this


await createComment(
        { identifier: userAuth.user.id, body: commentBody },
        publication._id
      );

mutate(`${process.env.URL}/api/publication`);

For this

 mutate(
        `${process.env.URL}/api/publication`,
        async (allPublications: Ipublication[]) => {
          const { data } = await like(
            { identifier: userAuth.user.id },
            publication._id
          );

          const updatePub = allPublications.map(pub =>
            pub._id === data._id ? { ...data, likes: data.likes } : pub
          );

          return updatePub;
        },
        false
      );

What you are doing there, is to update cache with the data that you'll receive data from the API's action, and you put it in the cache, but, you have to put false as well so it doesn't revalidate again, i tried it out and it's working, don't know if i'll have problems with it in the future, but for knowm it works great !

Upvotes: 2

Related Questions