Next.js Discord

Discord Forum

Switched to client rendering because the server rendering errored

Answered
Northeast Congo Lion posted this in #help-forum
Open in Discord
Northeast Congo LionOP
I'm using a server action for getting the data through a server component and passing it onto a client component.
Answered by LuisLl
the way you use it is by wrapping your data fetching logic in unstable_cache. It takes 3 parameters:
1 - the function whose return value you wanna cache
2 - an array of cache keys Next.js uses to identify the cache [], you can leave it empty or add an identifier like ["name-of-the-resource"]
3 - an options object where you can set time based revalidation or tags that you can later hit with revalidateTag().
[See the docs here](https://nextjs.org/docs/app/api-reference/functions/unstable_cache)
const getExpenses = async () => {
  // your data fetching logic here
  // return data;
}

const cachedGetExpenses = unstable_cache(
  getExpenses, 
  ["expenses"], 
  {tags: ['expenses']},
)


So when you call cachedGetExpenses() (or whatever name), the first time it's called and the result is saved in cache, the next times you call the function, no matter how many times, you will not hit the data source and instead you will get the cached data back.

You will continue to generate the page dynamically per user request, but you won't be making more fetch calls. You can purge the cache and request fresh data if you call revalidateTag('expenses') or revalidatePath("/route-where-you-fetch-this-data") with the tags passed in the options object ( {tags : ['expenses']} ).
View full answer

14 Replies

I don’t know if you did that purposefully but you should not use Server Actions to GET data.

If you’re calling a Server Action to get data on the Server you could instead fetch the data directly inside the Server Component, and pass it down to your client component.
Northeast Congo LionOP
That make sense. I did use that because I'm calling that function for another server component.

I guess that was the problem. Thank you!
Northeast Congo LionOP
It does work. But, it will fetch on every request even if there is no changes to the data, right?

I saw some code that uses the unstable_cache, but I'm not really sure how to use it and what it is for.
Run npm run build and check if that specific page is being rendered as *static *or dynamic.
- If it renders as static then you will only fetch the data once at build time, will be the same data until you re-deploy.
- If it renders as *dynamic *then you will fetch the data once per request.

unstable_cache helps to cache the results of your operation so it doesn't have to run on every request even if you're rendering the page dynamically, per user request.
the way you use it is by wrapping your data fetching logic in unstable_cache. It takes 3 parameters:
1 - the function whose return value you wanna cache
2 - an array of cache keys Next.js uses to identify the cache [], you can leave it empty or add an identifier like ["name-of-the-resource"]
3 - an options object where you can set time based revalidation or tags that you can later hit with revalidateTag().
[See the docs here](https://nextjs.org/docs/app/api-reference/functions/unstable_cache)
const getExpenses = async () => {
  // your data fetching logic here
  // return data;
}

const cachedGetExpenses = unstable_cache(
  getExpenses, 
  ["expenses"], 
  {tags: ['expenses']},
)


So when you call cachedGetExpenses() (or whatever name), the first time it's called and the result is saved in cache, the next times you call the function, no matter how many times, you will not hit the data source and instead you will get the cached data back.

You will continue to generate the page dynamically per user request, but you won't be making more fetch calls. You can purge the cache and request fresh data if you call revalidateTag('expenses') or revalidatePath("/route-where-you-fetch-this-data") with the tags passed in the options object ( {tags : ['expenses']} ).
Answer
Northeast Congo LionOP
That's very helpful. Thank you so much!

One more question. For the function that will be cache, I'm doing it like this:

const cachedGetExpenses = unstable_cache(
  async () => {
  // your data fetching logic here
  // return data;
  }, 
  ["expenses"], 
  {tags: ['expenses'],
)


Does this negates the caching of the function call because it's creating a new function everytime? Or it does not really matter on this scenario?
I will make it like you did if it does
As long as you give it a function it will work, either it's an inlined callback like your example, or just the function reference like in my example.
Tho, I would highly suggest to move the functions to a separate file/folder where you put all the data access functions. This way you will be able to re-use them either in Server Components, Route Handlers or from Client components via something like React Query, just by handling the function.
// Either here on top outside the Component body, or in a diferent file
const getExpenses = unstable_cache(
  async () => {
    // your data fetching logic here
    // return data;
  }, 
  ["expenses"], 
  {tags: ['expenses']},
)

export default async function ExpensesPage(){
  // getExpenses() will be called the first time
  // the next times will return the cached data 
  const expenses = await getExpenses(); 
  // ...
  
  return (<>...</>)
}
@Northeast Congo Lion make sure to mark the solution for the original question!
Northeast Congo LionOP
Alright! Thank you so much again!