Reputation: 681
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
Everything is great and fast, but, after making sure data is right, another post will appear because another user created it
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
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