skip to Main Content

I am trying to use unstable_cache on a server component to cache data in order to improve performance. However, it doesn’t seem working.

Below is my code. The fetchProductWithCache is called from react component render function every time when a request comes. The revalidate time is 10 seconds. I assume all requests within 10 seconds shouldn’t call fetchProductWithDelay from fetchProductWithCache method. However, I can see every request has 1 second latency and the log fetch product from unstable_cache is printed on every request. So it seems the unstable_cache doesn’t really cache anything.

What am I doing wrong?


export const runtime = 'edge'; // I want to deploy to all edge locations
export const revalidate = 10;

const fetchProductWithCache = async (country?: Country) => {
  const product = await unstable_cache(
    async () => {
      console.log('fetch product from unstable_cache');
      return fetchProductWithDelay(country);
    },
    ['product'],
    { revalidate: 10, tags: ['product'] }
  )();
  return product;
};

export const generateStaticParams = async () => {
  const countries = await api.product.countries();
  console.log('[PRODUCT] generating static paths:', countries);
  return countries.map((country) => ({ country }));
};

export default async function Page({ params }: { params: Props }) {
  const { country } = params;
  console.log('[PRODUCT] generating static product:', country);
  const product: any =  await fetchProductWithCache(country)
  const parityPrice = getDiscountedPrice(product.price, product.discount);

  if (Object.keys(country).length === 0 || country === null || !product) {
    return <div />;
  }
  return (
    <>
      <div className="ml-14 lg:ml-24 -mb-40 lg:-mb-56">
   ...

2

Answers


  1. The unstable_cach should be used to wrap the whole function (fetchProductWithCache)

    export const fetchProductWithCache = unstable_cache(
        async (country: string) => {
           return fetchProductWithDelay(country)
        },
        ['product'],
        { revalidate: 10, tags: ['product'] },
    );
    
    
    Login or Signup to reply.
  2. I cannot comment yet, but to clarify Josh Fradley’s answer:

    The problem with your code is that it is calling unstable_cache() every time you call fetchProductWithCache. The code is creating a new instance of the cached function for each call to fetchProductWithCache, effectively creating a new independent cache entry but for the same key. This is very prone to race conditions in regards to the cached data returned. It is just plain incorrect.

    The correct way is to do what Josh Fradley wrote. Declare your cached function once, meaning only call unstable_cache() once for the function you want to cache. Then call that function with your argument for country.

    So replace your declaration of fetchProductWithCache with his and it should work.

    BTW, just a heads up. You cannot mix time based revalidation with tags.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search