Always seems to cache on vercel
Answered
Brouillard posted this in #help-forum
Hi I have a problem only appearing on production, I'm using vercel to host my website.
After the build, if I go to a page that list users, I can correctly see them.
The issue comes next :
I delete a user, refresh the page. And the user still appear on the list.
Connecting to the db I can see that he's been deleted corectly.
I'm using "cache: 'no-store'" on the client component, and also :
"
headers: {
'Cache-Control': 'no-store'
}:
"
on my api, I also tried to put a timestamp in the query
all end up with the same response.
Please help ! I'm hopeless
After the build, if I go to a page that list users, I can correctly see them.
The issue comes next :
I delete a user, refresh the page. And the user still appear on the list.
Connecting to the db I can see that he's been deleted corectly.
I'm using "cache: 'no-store'" on the client component, and also :
"
headers: {
'Cache-Control': 'no-store'
}:
"
on my api, I also tried to put a timestamp in the query
all end up with the same response.
Please help ! I'm hopeless
47 Replies
Asiatic Lion
I am having the same problem. Please need help ASAP.
feel good not to be alone he he
Asiatic Lion
Yes one of my clients app suddenly stopped working as expected. And I cannot find a solution to it.
same here
Giant panda
i was with the same problem, as a quick fix i started using SWR, using timestamp in the api calls and for now i don't have that problem but still trying to get a better solution
I tried with the timestamp but it didn't work
I have one api endpoint where I manage to avoid the problem but I'm still figuring out how
Giant panda
@Brouillard you can use SWR depending on your case to try to fix it for now.
this works for me:
this works for me:
"use client";
import useSWR from 'swr';
import { useEffect, useState } from 'react';
export default function Page() {
const [key, setKey] = useState(() => `/api/cansee?timestamp=${Date.now()}`);
useEffect(() => {
setKey(`/api/cansee?timestamp=${Date.now()}`);
}, []);
const { data, error } = useSWR(key, {
revalidateOnMount: true,
});
if (error) return <>Not Allowed.</>;
if (!data) return <>Loading...</>;
return(
<div>
ok
</div>
);
}but this feels so dumb, idk, i'm sure there is a better way
And when you delete the user, use a server action then revalidatePath(that page) inside that server action
@joulev Add export const revalidate = 0 to the page
Giant panda
for some reason, this works few times, then it just doesnt work, then it works again, idk, maybe i'm doing it wrong but that doesn't seems to work at all
@Giant panda for some reason, this works few times, then it just doesnt work, then it works again, idk, maybe i'm doing it wrong but that doesn't seems to work at all
Well, I can’t tell. It has always been working to me, so I certainly cannot know why it’s not working for you with this much information
it doesn't work
Well then I need to see some code, or ideally a minimal reproduction repository
@Giant panda <@278244603142995972> you can use SWR depending on your case to try to fix it for now.
this works for me:
jsx
"use client";
import useSWR from 'swr';
import { useEffect, useState } from 'react';
export default function Page() {
const [key, setKey] = useState(() => `/api/cansee?timestamp=${Date.now()}`);
useEffect(() => {
setKey(`/api/cansee?timestamp=${Date.now()}`);
}, []);
const { data, error } = useSWR(key, {
revalidateOnMount: true,
});
if (error) return <>Not Allowed.</>;
if (!data) return <>Loading...</>;
return(
<div>
ok
</div>
);
}
Asiatic Lion
I am using zustand for global state i trying to avoid changing all into swr, but if there is no other way ill have to do that
@Asiatic Lion I am using zustand for global state i trying to avoid changing all into swr, but if there is no other way ill have to do that
Giant panda
i think its way more easy to use SWR for things like just getting updated data and etc... but i was getting a lot of problems with the onmount thing so i had to do the Date.now to ensure that this thing doesnt load on mount anything outdated not even for seconds, it should already work that way but whatever..
here, a component that call the api :
'use client'
//some imports//
export const revalidate = 0
const UsersList = ({ listedObjectName = 'utilisateurs', agency }: { listedObjectName?: string, agency?: Agency }) => {
const session = useSession()
const [loading, setLoading] = useState(false)
const [users, setUsers] = useState<User[]>([])
useEffect(() => {
const getUsers = async () => {
setLoading(true)
const res = await fetch(`${process.env.NEXT_PUBLIC_URL}/api/users`)
if (!res.ok) {
toast.error('Une erreur est survenue lors de la récupération des utilisateurs')
}
const data = await res.json()
console.log('data', data)
if (agency) {
setUsers(data.filter((user: User) => {
if (!user.agencies) return false
return user.agencies.some(agency => agency.id === agency.id)
}))
} else {
setUsers(data)
}
setLoading(false)
}
getUsers()
}, [])
return (
<Card className='flex flex-col'>
<CardHeader>
<CardTitle>Liste des {listedObjectName}</CardTitle>
</CardHeader>
<CardContent>
{loading ? (
<div className="flex justify-center items-center h-full">
<LoadingSpinner />
</div>
) : (
<ul className='flex flex-col gap-2'>
{users.length > 0 ? users.map((user, i) => (
<li key={i} className="flex gap-5 items-center">
<Suspense>
{session?.data?.user?.role === 'SUPER_ADMIN' && user.email !== session.data.user.email && (
<UserDeleteConfirmationPopover className='h-6 w-6' email={user.email} />
)}
</Suspense>
<p>{user.email}</p>
</li>
)) : (
<p>Aucun utilisateur trouvé</p>
)}
</ul>
)}
</CardContent>
</Card>
)
}
export default UsersListhere, the route.ts of /api/users :
import { NextRequest, NextResponse } from "next/server"
import user from "@/lib/user"
export async function GET(
request: NextRequest,
) {
const users = await user.getAll()
if (!users) {
return NextResponse.json({ error: "No user found" }, { status: 404 })
}
return NextResponse.json(users)
}I was calling it in a server component before
okay
Giant panda
const res = await fetch(`${process.env.NEXT_PUBLIC_URL}/api/users`, {
cache: 'no-store'
});have u tried this ?
yep
Giant panda
try what joulev said, and you can still use SWR btw.
@Giant panda jsx
const res = await fetch(`${process.env.NEXT_PUBLIC_URL}/api/users`, {
cache: 'no-store'
});
That won’t work because the cache no store thing is only applicable to fetches on the server. On the client it has no effect. The cause of the bug is that the api route is being statically generated instead of dynamically run at runtime
Btw since the fetch takes place on the client, you don’t need to put the domain there. fetch(/api/users) works
@joulev Add the revalidate export here
it works !
thanks a lot
Asiatic Lion
@Brouillard did you also added this And when you delete the user, use a server action then revalidatePath(that page) inside that server action ?
Since they are using client side data fetching, whatever I said about server actions and revalidatePath doesn’t apply
Asiatic Lion
what should I do since i am calling /api/categories from a zustand global state?
i added export const revalidate=0 to the route but it doesnt work
it is weird that you have this problem on a put
shouldn't it bu a GET ?
Asiatic Lion
in the past i had this same problem, and solve it by changing it into a put.
Im going to try changing it into a get to see what happens
Asiatic Lion
not working neither
Have you tried with export const revalidate = 0 at the beginning of the file ?
Asiatic Lion
let me try that
Asiatic Lion
i put it like this but it still doenst work