Next.js Discord

Discord Forum

How to cache data with server actions

Answered
JChicano posted this in #help-forum
Open in Discord
Avatar
Hello everyone, I'm performing my queries using server actions. The process is illustrated in the images below. I know that if you use fetch the data is cached by default, but with server actions this doesnt happend, what should I do?
Image
Image
Answered by JChicano
{cache: 'force-cache',
next: { tags: ['public-posts'], revalidate: 3600 } 
It was this line, i thought that the method GET cached by default, but without this is not doing it
View full answer

26 Replies

Avatar
@JChicano Hello everyone, I'm performing my queries using server actions. The process is illustrated in the images below. I know that if you use fetch the data is cached by default, but with server actions this doesnt happend, what should I do?
Avatar
server actions shouldn't be used to fetch data. Technically it is possible, but in the first way they are made to mutate data serverside.
Another thing that you want to use is a clientside fetching library. Without it you can lose control over your data pretty fast. SWR or React Query are examples.
Another thing that you also need to know is that you should fetch data serverside and then pass it via props to the client. That makes your page load faster
To solve your issue: use unstable_cache to cache third party results
Avatar
Anyway, I pass the information to the client component via props since it is wrapped in a <Suspense>, but what I should do is use React Query for queries (selects), and for inserts, deletes, or updates, I can continue using server actions, right?
Avatar
@JChicano And with React Query, since the results come through a fetch, would they be cached automatically? Could you give me an example of how to make that query from a server component, like the main page page.tsx?
Avatar
yes, you can fetch on the server side directly and pass the results to the client:
export default async function Page() {
  const data = await fetch('https://your.api/your/endpoint')
  const posts = await data.json()

// or directly render them and move the code that needs interactivity into it's own component and mark only them as client component
  return (
    <Posts posts={posts}/>
  )
}
Avatar
happy to help
Avatar
Transvaal lion
what worked for me was to have an /api/ endpoint and some helper functions for grabbing the data. Then the requests get cached
I added a console.log to the database query, and it executes every time, this indicate that it is not being cached right?
Avatar
Transvaal lion
you could add your own headers to the req
export async function GET(req, { params }) {

try {
const { slug } = await params;
const { article, articleError } = await fetchSingleArticle(slug);
if (articleError) {
return new Response(JSON.stringify({ error: articleError.message }), {
status: 500,
headers: {
'Content-Type': 'application/json',
},
});
}

return new Response(JSON.stringify({ article }), {
status: 200,
headers: {
'Cache-Control': 'public, s-maxage=3600, stale-while-revalidate=59',
'Content-Type': 'application/json',
},
});
} catch (error) {
return new Response(JSON.stringify({ error: error.message }), {
status: 500,
headers: {
'Content-Type': 'application/json',
},
});
}
}
Avatar
Transvaal lion
export const apiFetchPosts = async ( { category, subcategory, region, search, page, pageSize } ) => {
try {
const req = await fetch(${process.env.NEXT_PUBLIC_BASE_URL}/api/get-public-posts?category=${category}&subcategory=${subcategory}&region=${region}&search=${search}&page=${page}&pageSize=${pageSize}, {
cache: 'force-cache',
next: { tags: ['public-posts'], revalidate: 3600 }
});

if (!req.ok) {
throw new Error(Failed to fetch Regions: ${req.status});
}
const response = await req.json();
return response;
} catch (error) {
console.error('Error fetching regions:', error);
throw error;
}
};
just some mumbo jumbo code, but you get the idea
Avatar
Oh, right, in the URL. Thank you so much! I'll give it a try.
Avatar
yep, now its working finalyyyy
Answer
Avatar
Transvaal lion
Indeed, it’s something they changed in nextjs 15. Force cache was on by default in prev versions
Avatar
if the data has to be updated with this it will be do it right?
revalidateTag("user-data");
'pubic-posts' (to continue with the same example)
Avatar
Transvaal lion
This will clear the next cache but you will see the content change after the time you set in the headers expires i think. Try to test it out
Avatar
Yes, it works like that, but I wanted to force an update when the user modifies their data so that the new changes are reflected immediately.
Avatar
Transvaal lion
i was also searching for that for a long time and couldn/t make it work, at least not when hosting it on vercel
Avatar
for me with the revalidateTag() function is working, i have it in localhost, you think that hosted in vercel it wont work?
Avatar
Transvaal lion
Indeed, on vercel you won’t be able to clear the cache on demand, it will only clear the next cache but the vercel one will wait for the headers expiration time