Next.js Discord

Discord Forum

revalidating on page load

Unanswered
English Spot posted this in #help-forum
Open in Discord
English SpotOP
Is there a nice, not hacky way to accomplish this? Eg. We have a /[userid] page. I visit, next caches this, I leave. Then after I’ve left, that user updates their info. I then go back and am left with stale data.

I’ve come up with a somewhat annoying way by doing revalidatePath in a useEffect, but then since this has to be a client comp, I get left with annoying data flows of indicating that this is revalidating.

Just wondering if anyone has an ergonomic way to accomplish this.. feels like it should be exposed by next, not a repeated implementation by me

128 Replies

English SpotOP
It will eliminate stale data in my cache
Call an action from a use effect that revalidates*
The revalidate doesn’t fix the behavior I’ve described above
Because revalidateTag/path works the next time you visit
I dont even know what's the reason you are using a useEffect to call the action.
English SpotOP
Someone visits my profile, they have it cached, and then leave. In the meantime I update my username say, I revalidate, now my cache is not stale. Their cache is still stale. They go back to my page and my username is out of date
Are you using a server action or a route handler? To fetch the data?
Plott Hound
yes please explain exactly what happens when you "I update my username say"
English SpotOP
Run a server action and revalidate path
@English Spot Someone visits my profile, they have it cached, and then leave. In the meantime I update my username say, I revalidate, now my cache is not stale. Their cache is still stale. They go back to my page and my username is out of date
That shouldn't happen. If you revalidate then as long as the other guy refreshes/goes back to the page after a navigation, he shouldn't be getting stale data
English SpotOP
Refresh fixes, client nav remains stale
Then i feel like your revalidate isnt working
English SpotOP
Isn’t revalidate just fixing your own cache? There’s no such state like fanned to all users
I mean my data refreshes when the action completes, idk what else could be going wrong
From a like mechanical perspective, I don’t see how revalidating would be fanned out to other users and their cache? This behavior kinda lines up with my mental model of the caching behavior. Am I missing something ??
@English Spot quick question, when you say you leave and come back.. do you close the page? or just.. change tabs?
English SpotOP
Apologies, I mean client nav (go to the homepage and then head back to the user’s page, all routing is client side via react at this point)
There’s 2 outcomes here
1. There’s no way to do what I’m trying to do without resetting the cache on page load
2. I’m misunderstanding the architecture, and revalidatePath/tag should work but I’ve implemented wrong

If 1 is the case, then I’m not explaining the problem correctly perhaps, as everyone has suggested fixes that seemingly don’t work for me . If 2 is the case then I can post code and get to the bottom of the implementation flaw
yea post the code plz
English SpotOP
But mechanically speaking, if I do revalidatePath() and say to next “hey my cache is out of date, go revalidate it” after I update my username or something, I’m seriously struggling to understand how this would somehow tell every other user of the site who has my profile page cached that their cache also needs revalidating ??
Before I bother posting code, I’m looking for an answer to this
ok so how it works is that nextjs caches gloablly
when you make a request for the first time (if no other user went there) thats when nextjs fetches all the data, and sets up the cache headers
thats stored in .next
on further requests nextjs directly serves the cached data until the cache is revalidated when the process repeats itself.
English SpotOP
Ok. So this is simply not possible without client side revalidation logic, correct?
I have two conflicting answers here lol
English SpotOP
Yea I understand how to accomplish it, my original question was if anyone has found a more ergonomic way to accomplish this
use a server action
English SpotOP
Mounting client component with a useEffect that nukes the cache on page load is less than ideal
you wont need to do router.refresh()
use server action to update the info and calling revalidatePath inside it
@English Spot Yea I understand how to accomplish it, my original question was if anyone has found a more ergonomic way to accomplish this
if you want real-time then no. server action is not the way. if you don't need real-time then yes server action
you seem to want real time in that case use ws
English SpotOP
It’s not even a matter of real time
Like I agree
But this is a very solved problem in client render land
send us your code
English SpotOP
RQ handles it very graciously
your mutation code, fetching code.
@English Spot It’s not even a matter of real time
if it is not real time then why do you want other users to see the changes instantly?
@English Spot RQ handles it very graciously
RQ does it by faking real-time. i did say about it in the message

or you can also fake real-time by running router.refresh() on tab focus – but all of this you have to implement yourself and server actions are not designed for this purpose
RQ/swr calls something like router.refresh() when you focus on the tab again
which is not real time, just a fake real time
English SpotOP
Yea that is sufficient for what I’m building
for server actions, this is not built in but you can manually implement that yourself
English SpotOP
Yea this was the point of my question. Has anyone come up with a more ergonomic solution to revalidating on page load. Mounting a client comp for useEffect to nuke the cache is not a good dx (or ux bc images flicker )
Answer seems to be a no
you can combine SSR with RQ/SWR and that is actually my go-to choice when I build complex stuff like dashboards etc
fetch in server component, then use it as the initial value in RQ/SWR and refetch again with client side rendering
English SpotOP
Yea that’s likely the answer, I’ve been trying to lean for less deps. This just feels like something that should be a next utility, instead of something I’m building myself with primitive
next is on the server side mainly, on the client side state-of-the-art solutions like RQ are perfect already so i dont think the next guys see it a worthwhile investment to do the client-side as well
English SpotOP
Well sure I don’t expect them to reinvent a client fetch/cache solution as robust as RQ
But even in server land this is a solved issue in MPAs. This issue is unique to the hybrid SSR/SPA mode that next has
And thus, having a native solution to “I want each refetch of this page to not used cached data if it’s stale” is not a crazy ask to me
well... whatever you expect, there isn't a built in way to do client-side rendering in nextjs. server-side rendering is shot-then-forget, nextjs server doesn't maintain a connection with the browser clients so doesn't send new data when it is updated
what RQ does, as i told you, is on the client-side which means client-side rendering
English SpotOP
This may be one of the sole unique problems with nextjs/RSCs then
Because the data fetch is tied to the component, idk if they can refetch strictly the data
i dont see how it is a problem though. can you clarify how you would implement it in a MPA?
say we are in very basic land. express backend, html/css/js frontend
how would you do this?
if i get what you try to do i might be able to translate that to next
English SpotOP
I mean Remix and SvelteKit do just this. First request is SSR, subsequent requests are CSR. SvelteKit will re-run the loader function on client navs and we get updated data in such a case
in that case it includes client side rendering which, as i told you, next doesn't implement because RQ is too good already
English SpotOP
This would work in pages router though..
how would you do it in the pages router without RQ?
English SpotOP
gssp gets re run
I’m not worried about on tab focus. I’m talking about subsequent navs to a route
subsequent navs to the route are subjected to the router cache, when that cache expires the server component gets rerun too
the router cache is the only difference here
English SpotOP
If I hit a page, next caches it. I go to a different route. In the meantime, the data associated with my cached page is updated. I hit the page again.
App router -> stale data if the cache hasn’t expired
Pages router -> correct data as gssp re runs
Remix/Svelte -> correct data as page loader re runs
@English Spot If I hit a page, next caches it. I go to a different route. In the meantime, the data associated with my cached page is updated. I hit the page again. App router -> stale data if the cache hasn’t expired Pages router -> correct data as gssp re runs Remix/Svelte -> correct data as page loader re runs
app router:

1. if you update the cached page in the same browser tab using server action, the cache is invalidated by revalidatePath/revalidateTag -> updated data

2. if you update the cached page in a different browser tab/browser/device, the cache is preserved -> stale data

both of these are expected behaviours
English SpotOP
I understand it’s expected
I’m saying that the problem is non-existent in other frameworks and literally the previous iteration of this framework
Thus, expecting a solution is not in any way out of scope
the reason why the router cache is there in the first place is because, say you are on tab A, then click tab B, then click back to tab A. without the router cache it will flood your server.

since the change to the value is not made in the same browser tab, react/next considers the stale value to be "good enough" and not worth spamming your server too much.

this is why they introduced the router cache. it is controversial and gets a lot of hate, but once you see it you see why it is a good idea. btw the author of RQ hinted at adding such a cache to RQ in the future
what you want is just a turn-off of the router cache, which won't happen as it is a feature. plenty of people wanted that as well but they refused
if you want data that is guaranteed to be fresh at all time, use real-time or RQ+route handler
data that is guaranteed to be fresh at all time is not doable in server components, nextjs didn't design the app router for such data
so dashboard data for example should be client side rendered
if you want to see your portfolio when you invest in stocks for example, client side rendering is a must
English SpotOP
Ok I mean this isn’t getting anywhere as I guess i disagree w the philosophy, but I appreciate your response as everyone else just said “just revalidatePath”. This is a limitation of binding all data fetch to the component tree, as the router can’t easily just refetch on page load, it would have to rerender the entire component, at which point the cache is useless yes. Though I pretty much disagree that any data that’s expected to be fresh needs client fetching. Other SSR first frameworks don’t have this issue
This is a mostly static site I have. I would just like to have fresh data without involving an entire client side fetching/cache solution lol
this is a feature to reduce the server load. i get why you think it is bad, but it just won't go away so you have to use client side rendering. it is a design decision by next, hence next has it but not remix
it's just a hard truth so well... we have to get used to it
English SpotOP
Yes and that’s fine because I can do {staletime:0} if I want lol
yeah you can switch off. nextjs decided that you cannot switch off at all. bad move i believe, but what choice do i have anyway
btw there is a discussion ongoing in vercel/next.js where a team member proposes an export to control this value
something like export const routerCacheRevalidationPeriod = 10
but afaik it hasn't been implemented yet
so right now, it is a hard 30s that you must live with, no other choice
English SpotOP
I mean this is likely an obviously glaring hole lol. For all the nonsense complaints next gets this is far and away the most valid concern
either way, i think we have come to a conclusion. have fun coding, and i believe you are installing RQ right now :)
English SpotOP
No lol
I’m not involving a whole client fetch library for an app that is like 1% interactive
I’ll just live with the stale data for 30secs or go back to pages router for this one page
hmm in that case you have to live with data that may be stale by a bit
yeah or go to the pages router – that is a good idea
btw swr is pretty lightweight and can do this well also, no need to bring RQ
English SpotOP
I can also just revalidate the current path in a useEffect I suppose
yeah, plenty of workarounds the router cache
English SpotOP
I was just hoping someone had a prebuilt comp that does this nicely
choose the one you see fit
English SpotOP
Last part; is there a reason that noStore doesn’t solve this?
Am I misunderstanding the purpose of that
the router cache is global in the app router, you cannot control it at all. it doesn't care about anything you configure in your code including no store
English SpotOP
So then what is it for ?
@English Spot So then what is it for ?
no-store is just telling nextjs that this fetch() should be dynamically rendered
because by default fetch() are static
this is the data cache and not related to the router cache which is purely client side and cannot be disabled
English SpotOP
Man the docs need a rework
Nothing about the noStore doc makes this clear at all lol
@English Spot Man the docs need a rework
you should read [this page](https://nextjs.org/docs/app/building-your-application/caching) to understand how caching work in nextjs
English SpotOP
Yea I’ve seen it I do need to go through it again, though I stand by my take that the docs need a rework
Granted that fn is unstable so fair, but still
English SpotOP
hate to revive this thread. but now that i'm using unstable_cache and revalidatePath() I don't get the stale data behavior anymore 😕 ??
nevermind... getting lots of inconsistent behavior