Next.js Discord

Discord Forum

Stale data on client-side navigation

Answered
West African Crocodile posted this in #help-forum
Open in Discord
West African CrocodileOP
I have a main page which adds data to my database using a form and server actions. When I add a record and then navigate using a <Link> component to /history which just fetches and renders all the existing records (via await prisma.workday.findMany()) the data is stale and doesn't contain the newly added record. The data isn't stale after I refresh, but that's cumbersome. How can I fix this problem?
Answered by joulev
or call revalidatePath + force-dynamic + prefetch={false}
View full answer

80 Replies

@aardani use react query to refresh the stale data on mount
West African CrocodileOP
I'd prefer not to change my components to be client ones
I thought that maybe dynamic = 'force-dynamic' or revalidate = 0 would do the trick but they don't, why is that?
if you don't spam for ~ 30 seconds they will refetch
but if you spam it they wont get refreshed haha
@aardani they do, but hard navigation are cached for ~30 seconds :))
West African CrocodileOP
So I've just tried waiting 30s after adding data to my db and after navigation the data is still old
hmm das weird
how did you fetch the data?
using fetch() ?
West African CrocodileOP
export default async function History() {
    const allWorktimes = await prisma.workday.findMany();
    ...
}
did you wait 30 second then move another route then back to the same route
or did you just wait 30 seconds and do nothing 🫠
West African CrocodileOP
I added data on my root page, I waited 30s and I navigated to /history using <Link />
hmmmm das weird, make sure you didn't hover it though since hovering it will prefetch the data ahead of time
@aardani they do, but hard navigation are cached for ~30 seconds :))
interesting, didnt know this
where did you find out about this
@joulev where did you find out about this
i have a repro repo, wait a sec, testing it again to make sure im not insane 😶‍🌫️
or call revalidatePath + force-dynamic + prefetch={false}
Answer
@joulev this behaviour is documented and called 'soft navigation'
West African CrocodileOP
I've read about it a bit, but as I said later I tried using dynamic = 'force-dynamic' and revalidate = 0 in /history but it still didn't work
I also call revalidatePath('/') on the end of my server action
and prefetch={false} doesn't do anything in dev right? only prod
I might try the <a> tag approach
@joulev or call `revalidatePath` + `force-dynamic` + `prefetch={false}`
well this combo is working for me :MeguShrug:
atleast the RSC is prerendered again, and awaits are awaited again, not sure about the data
West African CrocodileOP
Ok I'll try it one more time, but I think waiting 30s also just worked, but that's still not a good solution to me
30 seconds is such a random number so idt that is the case
without specialised configuration
@joulev 30 seconds is such a random number so idt that is the case
it may have +-3 seconds since im using a windows clock timer lmao
i couldn't figure out where they store the cache so i didnt know the exact time
@joulev 30 seconds is such a random number so idt that is the case
West African CrocodileOP
yeah nvm the waiting hasn't worked rn
@joulev well this combo is working for me <:MeguShrug:786714517711224852>
West African CrocodileOP
you know what actually the prefetch={false} makes all the difference, I don't even need force-dynamic idk wtf that's used for then but well yeah it works now the data is always fresh
use all of them mwa ha ha ha
West African CrocodileOP
I have no clue man
probably you used headers() or cookies() somewhere
West African CrocodileOP
no
💀
West African CrocodileOP
import prisma from '$lib/db/prisma';
import { formatWorktime, round } from '$lib/utils';

export default async function History() {
    const allWorktimes = await prisma.workday.findMany();
    const dateFormatter = Intl.DateTimeFormat('en-UK', { dateStyle: 'long' });
    return (
        <ol className="worktime-list">
            {allWorktimes.map(worktime => (
                <li key={worktime.id}>
                    <h2>{dateFormatter.format(new Date(worktime.date))}</h2>
                    <p>Worktime: {formatWorktime(worktime.worktime)}</p>
                    <p>Earned: {round(worktime.earned, 2)}zł</p>
                </li>
            ))}
        </ol>
    );
}
well if it works it works
West African CrocodileOP
this is my entire page.tsx
probably an upper layout.tsx is dynamic
idk
that is likely the case
West African CrocodileOP
no I only have one layout.tsx
oh wait, if you did call revalidatePath probably that means the thing is revalidated
so no need of dynamic
hmm interesting
i think i have some code changes to do in my apps
where did you put revalidatePath?
@joulev i think i have some code changes to do in my apps
but is it ok though to put revalidatePath on every user navigation. wouldn't it affect the server?
West African CrocodileOP
export default async function Home() {
    async function addWorkday(data: FormData) {
        'use server';

        // ...

        revalidatePath('/');
    }
// ...
}
here
@aardani but is it ok though to put revalidatePath on every user navigation. wouldn't it affect the server?
no, i only use revalidatePath in server actions, like how it is supposed to be used
i thought you put it in server comps hah
well nextjs works in some magical way no one knows why again
glad it worked for you
@joulev no, i only use revalidatePath in server actions, like how it is supposed to be used
do you have to do anything after the server action has finished running? like router.refresh or somethin
since mutation is released i can no longer claim i know how nextjs works anymore
ah no, i don't redirect after server actions
but i do revalidate all pages
and after that if i use next/link prefetch=false to navigate to any pages
it shows updated data
@joulev so no need of dynamic
West African CrocodileOP
but then if I don't have revalidatePath() but I do have force-dynamic in /history it doesn't work again
what's the point of force-dynamic does it even work correctly
ok wait tf is it actually mandatory to wait that 30 or smthn seconds because I did that again out of curiosity and it worked
💀 umm
just next.js working in some black magic man, this is beyond humanity comprehension
West African CrocodileOP
this is obviously not my ideal solution I'm going back to the revalidatePath one, but it's interesting
make sure you also erase .next folder to be sure that it don't cache anything every time you change the dynamic/static of a route (?)
West African CrocodileOP
that's next level 💀
nextjs level? :noice:
West African CrocodileOP
exactly
anyway it works properly the data is fresh on every nav so ty guys