How to properly fetch data inside the like button?
Unanswered
kkkotiqqq posted this in #help-forum
I use next js 14. I have comments, which I receive by api, inside the comment there is a like button, I need to somehow get data on whether the user has already liked this comment, please tell me the correct algorithm how to implement this, or several
8 Replies
Kurilian Bobtail
you can either have the button an RSC that fetches the data (whether user liked it or not) for that very comment, and pass it on to (wraps a) client component to handle onClick client-side.
Alternatively, a more performant approach is to fetch that piece of info for all comments in the parent component, and pass it on directly to a client-side like button instantiated for each comment.
Alternatively, a more performant approach is to fetch that piece of info for all comments in the parent component, and pass it on directly to a client-side like button instantiated for each comment.
@Kurilian Bobtail you can either have the button an RSC that fetches the data (whether user liked it or not) for that very comment, and pass it on to (wraps a) client component to handle onClick client-side.
Alternatively, a more performant approach is to fetch that piece of info for all comments in the parent component, and pass it on directly to a client-side like button instantiated for each comment.
I have now implemented approximately as the second method as you described, but there is a nuance, it turns out that each request on the site to receive comments must be authorized, and in fact it will not be cached for authorized users, since the beareer token is different for everyone, the api request will be perceived as a separate and not cached?
Kurilian Bobtail
you are implementing it using app router and RSCs, right? where are you fetching data, within RSC? Or do you mean you have an upstream API to which you pass token when doing
Regarding caching (React
fetch from an RSC?Regarding caching (React
cache), it is persistent for the request life-cycle, which involves one user anyway@Kurilian Bobtail you are implementing it using app router and RSCs, right? where are you fetching data, within RSC? Or do you mean you have an upstream API to which you pass token when doing `fetch` from an RSC?
Regarding caching (React `cache`), it is persistent for the request life-cycle, which involves one user anyway
i have function that fetch data from wordpress
I prepare a list of comments on backend side, and within each comment I fill in whether the user has liked the comment (to show the status of the likes), and send it to the front end
the like button calls this function, which revalidates the cache after sending a like
function getAuthorsComments({ token } : { token: string }) {
return fetch(
`https://site.com/wp-json/rztheadless/v1/author-comments?page=1&per_page=3`,
{
next: {
revalidate: 5,
tags: ["comments"],
},
headers: {
Authorization: `Bearer ${token}`,
},
},
).then((res) => res.json());
}I prepare a list of comments on backend side, and within each comment I fill in whether the user has liked the comment (to show the status of the likes), and send it to the front end
the like button calls this function, which revalidates the cache after sending a like
export const addLike = async (reviewId: number, token: string) => {
const response = await fetch(
`https://site.com/wp-json/rztheadless/v1/likes`,
{
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${token}`,
},
body: JSON.stringify({ review_id: reviewId }),
}
);
const responseData = await response.json();
if (!response.ok) {
throw new Error(responseData.message || "Failed to add like");
}
await fetch('/api/revalidate?tag=comments');
return responseData;
};Kurilian Bobtail
so, the first
getAuthorsComments happens server side, while the second addLike is a client side function that then calls a server-side endpoint (/api/revalidate). is that correct?@Kurilian Bobtail so, the first `getAuthorsComments` happens server side, while the second `addLike` is a client side function that then calls a server-side endpoint (`/api/revalidate`). is that correct?
yes 🙂 The only thing is that I made the like button not through server action, but in theory I can rewrite to it. the thing is that the like button needs some logic on the client that uses useEffect
this is code with logic:
this is code with logic:
const LikeButton = ({
reviewId,
initialLikesCount,
userHasLiked,
sessionId,
}) => {
// some useStates
useEffect(() => {
if (userHasLiked) {
setCanRemove(false);
}
}, [userHasLiked]);
useEffect(() => {
if (likeTimestamp) {
// time function that block interactive after some seconds
}
}, [likeTimestamp]);
const handleLike = async () => {
if (isLoading || !sessionId ) {
setIsDialogOpen(true);
return;
}
setIsLoading(true);
try {
if (liked && canRemove && removeCount < 1) {
await removeLike(reviewId, sessionId);
setLikes(likes - 1);
setLiked(false);
setRemoveCount(removeCount + 1);
setCanRemove(false);
} else if (!liked) {
await addLike(reviewId, sessionId);
setLikes(likes + 1);
setLiked(true);
setCanRemove(removeCount < 1);
setLikeTimestamp(likeTimestamp || Date.now());
}
toast({
description: liked
? "You remove like"
: "Like added",
});
} catch (error) {
const errorMessage =
error instanceof Error ? error.message : "An error occurred";
toast({
description: errorMessage,
});
} finally {
setIsLoading(false);
}
};
const handleClick = () => {
if (liked && !canRemove) {
// toast
} else {
handleLike();
}
};Kurilian Bobtail
yeah. three things:
1. move upstream api request to server side. within RSCs and server actions
2. your retrieval of data using fetch, if cached, is cached across users. either vary url to include user-specific id, or setup caching header that
3. your use of
1. move upstream api request to server side. within RSCs and server actions
2. your retrieval of data using fetch, if cached, is cached across users. either vary url to include user-specific id, or setup caching header that
Vary per auth header, or best make sure this fetch and similar caching is disabled.3. your use of
useEffect seems complicated. I did not follow the code you sent last because of that complexity, if it works then that's good... but then again check https://react.dev/learn/you-might-not-need-an-effect@Kurilian Bobtail yeah. three things:
1. move upstream api request to server side. within RSCs and server actions
2. your retrieval of data using fetch, if cached, is cached across users. either vary url to include user-specific id, or setup caching header that `Vary` per auth header, or best make sure this `fetch` and similar caching is disabled.
3. your use of `useEffect` seems complicated. I did not follow the code you sent last because of that complexity, if it works then that's good... but then again check https://react.dev/learn/you-might-not-need-an-effect
In a nutshell, the point of the like button is this:
a user can give a like and cancel it within 10 seconds, but only once, after 10 seconds the button is blocked on client side.
Accordingly, if the server responds that the user has already liked this comment, then he can't cancel it either.
a user can give a like and cancel it within 10 seconds, but only once, after 10 seconds the button is blocked on client side.
Accordingly, if the server responds that the user has already liked this comment, then he can't cancel it either.