Revalidate SSR image?
Unanswered
Yucatan Vireo posted this in #help-forum
Yucatan VireoOP
This may be a naive question, but what is the best way to go about revalidating an SSR'd <Image /> component? I want to SSR a currentUser's profile image, but I have no idea what the best way to do this is. I am currently using TanStack Query to take the SSRd image key as initial data and then I can revalidate this query whenever I want to get the current profile image as it changes... but it would be nice to just trigger revalidations if possible. However, I am guessing this isn't possible since revalidation is done at route-level if I'm not mistaken.
30 Replies
If you revalidate the query whenever the user changes their profile picture, the image component will receive the new source and update itself, all you need to do is revalidate the query, which I believe Tanstack Query provides.
Burmese
You could have profile data fetched from a server component, pass to the client component rendering Image, and then have that client component call router.refresh() to reload the page with the new image.
@Plague If you revalidate the query whenever the user changes their profile picture, the image component will receive the new source and update itself, all you need to do is revalidate the query, which I believe Tanstack Query provides.
Yucatan VireoOP
I have done this in the side nav, but on profile pages I think toying with the caching behavior makes more sense. Ideally, there should be some cache time on profile pages, and I should manually revalidate one specific profile (like the current user's, which I've done w/revalidatePath() but it doesn't seem to work).
@Burmese You could have profile data fetched from a server component, pass to the client component rendering Image, and then have that client component call router.refresh() to reload the page with the new image.
Yucatan VireoOP
This would work but I need to revalidate this data from outside of the component (revalidation happens when a new profile image is uploaded). I have called revalidatePath() inside my createProfileImage() tRPC, yet it only seems to reload the profile image sometimes when revisiting the profile page after updating the profile image.
@Yucatan Vireo This would work but I need to revalidate this data from outside of the component (revalidation happens when a new profile image is uploaded). I have called revalidatePath() inside my createProfileImage() tRPC, yet it only seems to reload the profile image sometimes when revisiting the profile page after updating the profile image.
I recommend using Server Actions for that user action and calling revalidatePath() inside the Server Action after a successful profile image change, this will update the router cache which only Server Actions can do with revalidatePath() allowing you to see the update without even refreshing.
@Plague I recommend using Server Actions for that user action and calling revalidatePath() inside the Server Action after a successful profile image change, this will update the router cache which only Server Actions can do with revalidatePath() allowing you to see the update without even refreshing.
Yucatan VireoOP
Ahhh, see I was using a regular function passed into a tRPC procedure. I’ll have to see if turning this function into a server action has any downsides here since it’s being called on the server.
To clarify, I was calling
revalidatePath(‘/main)/c/${username}’)which may be written wrong?@Yucatan Vireo Ahhh, see I was using a regular function passed into a tRPC procedure. I’ll have to see if turning this function into a server action has any downsides here since it’s being called _on_ the server.
Yeah it does have downsides for being called from the server instead of the client, and that is an extra network roundtrip, you can do anything you want in a Server Action from the server already so Server Actions should only really be called from the client. Not sure how to seamlessly integrate server actions with tRPC, but, I'm sure there are docs
Yucatan VireoOP
I’m on mobile.. this is a pain to write. I’ll play around with revalidatePath tomorrow and see what is best to do. Tbh, tRPC is not quite what I’ve hoped it would be. Lots of little gotchas. It seems really nice for fetching, but for mutations, Server Actions + vanillas TanStack Query are so pleasant.
@Yucatan Vireo I’m on mobile.. this is a pain to write. I’ll play around with revalidatePath tomorrow and see what is best to do. Tbh, tRPC is not quite what I’ve hoped it would be. Lots of little gotchas. It seems really nice for fetching, but for mutations, Server Actions + vanillas TanStack Query are so pleasant.
No worries, yeah personally, when working with Next.js specifically, I don't find tRPC that useful.
@Plague No worries, yeah personally, when working with Next.js specifically, I don't find tRPC that useful.
Yucatan VireoOP
I am probably going to drop it. I manually do auth checks on a per-route basis (so atm I don't need the tRPC context benefits) and I'm not a fan of wrapping the entirety of my app's fetch/mutation logic in tRPC.
One guy's solution to revalidating a path from a tRPC procedure was to define a context that could handle this trigger: https://www.answeroverflow.com/m/1159089518582968371#solution-1159116647110541372
Definitely going to just use a generic server action w/ React Query instead. More tRPC disappointment..lol
One guy's solution to revalidating a path from a tRPC procedure was to define a context that could handle this trigger: https://www.answeroverflow.com/m/1159089518582968371#solution-1159116647110541372
Definitely going to just use a generic server action w/ React Query instead. More tRPC disappointment..lol
I have a follow up question to this. We use the user's ID as their profile image path so we can aggressively cache on the CDN. We bust the cache when they upload but because the URL stays the same I'm not sure router.refresh would fetch the new image with the same SRC. Is there wany way to force the Image component to reload? I guess could do some hacks with mounting and dismounting
@Matt I have a follow up question to this. We use the user's ID as their profile image path so we can aggressively cache on the CDN. We bust the cache when they upload but because the URL stays the same I'm not sure router.refresh would fetch the new image with the same SRC. Is there wany way to force the Image component to reload? I guess could do some hacks with mounting and dismounting
Well it has a minimumCacheTTL of 60s by default so the image component should receive the new image after that period, there is no way to manually invalidate the image cache currently which is why a low minimumTTL is recommended.
It's a remote resource with optimize=false, would it still use the image cache?
Yes it just won’t run image optimizations on the next.js server
The source is still cached
How is that possible, the image is pulled straight from our CDN?
Like if I remove this Image component and remount it how could it pull a cached version?
That’s a next image component unoptimized?
Yeah
That’s my mistake then, I was under the impression that it only avoided running image optimizations for format conversion and large source set generation
If this is the case as long as the cache is busted router.refresh() should fetch the fresh image
Yucatan VireoOP
Hey, here is my simple solution (for now, since I'm not totally ready to drop tRPC so hastily):
Since calling a
const {
mutateAsync: createProfileImage,
isPending,
isSuccess: createProfileImageSuccess,
data,
} = trpc.createProfileImage.useMutation({
// onError: removeUploadedFile,
onSuccess: () => {
revalidatePathAction(`/c/${user?.username}`);
setDialogIsOpen(false);
utils.getCurrentUserProfileImage.invalidate(); // This is for the side nav profile image, ignore this
},
});Since calling a
revalidatePath() does seem to only in Server Actions (documentation doesn't mention this), I just wrapped it in a Server Action and called from the client once profile image creation is succesful. Please roast me, I'm sure I deserve it 🤣@Yucatan Vireo Hey, here is my simple solution (for now, since I'm not totally ready to drop tRPC so hastily):
TypeScript
const {
mutateAsync: createProfileImage,
isPending,
isSuccess: createProfileImageSuccess,
data,
} = trpc.createProfileImage.useMutation({
// onError: removeUploadedFile,
onSuccess: () => {
revalidatePathAction(`/c/${user?.username}`);
setDialogIsOpen(false);
utils.getCurrentUserProfileImage.invalidate(); // This is for the side nav profile image, ignore this
},
});
Since calling a `revalidatePath()` does seem to only in Server Actions (documentation doesn't mention this), I just wrapped it in a Server Action and called from the client once profile image creation is succesful. Please roast me, I'm sure I deserve it 🤣
Documentation does mention that only server actions can invalidate the router cache when calling revalidatePath or revalidateTag, it’s in the caching portion of the documentation
I can grab a link shortly
Yucatan VireoOP
They should reiterate this here: https://nextjs.org/docs/app/building-your-application/caching#revalidatepath
Orrrrr I can just be more thorough next time!
Orrrrr I can just be more thorough next time!