Next.js Discord

Discord Forum

Why `unstable_cache` don't cache same request made multiple time in the same start time ?

Unanswered
California pilchard posted this in #help-forum
Open in Discord
California pilchardOP
Okay Im just learning how to properly cache in NextJS. I could use "use cache" but still unstable. SO my only solution is unstable_cache, so I have this testing function :
export const getTest = async () => {
    return await unstable_cache(
        async () => {
                        console.log('hello from getTest');
            ...
            return data;
        },
            ['test'],
        { revalidate: 10 } // 10sec for testing
    )();
};

But I dont know why, if I do the same request multiple time from layout.tsx and page.tsx (children), that call multiple time my function without being cached :
MOVIE LAYOUT RENDERING
LANG LAYOUT RENDERING
hell from getTest # from layout.tsx
hell from getTest # from page.tsx
hell from getTest # from page.tsx (generateMetadata)

Am I missing something ?

14 Replies

@joulev unstable_cache caches across request but does not dedupes within the same request (don't ask me why) hence, just use it in combination with `React.cache` and you are set
California pilchardOP
Do u know where I can find an example of combination of unstable_cache and cache from react ? Because Ive test some stuff but isnt working... Btw use cache work really well :
hello from getTest
 Cache  hello from getTest
 Cache  hello from getTest
@California pilchard Do u know where I can find an example of combination of `unstable_cache` and `cache` from react ? Because Ive test some stuff but isnt working... Btw `use cache` work really well : sh hello from getTest Cache hello from getTest Cache hello from getTest
just wrap the function inside cache
export const getTest = cache(() => {
    return unstable_cache(
        async () => {
                        console.log('hello from getTest');
            ...
            return data;
        },
            ['test'],
        { revalidate: 10 } // 10sec for testing
    )();
});


Btw use cache work really well :
no comment from me, i have never used use cache
@joulev just wrap the function inside `cache` tsx export const getTest = cache(() => { return unstable_cache( async () => { console.log('hello from getTest'); ... return data; }, ['test'], { revalidate: 10 } // 10sec for testing )(); }); > Btw use cache work really well : no comment from me, i have never used use cache
California pilchardOP
I dont understand why in my case isnt working, I do the same thing :
======Fetching movie with media key: [ 'fr-FR', 'movie', '1087192' ]
======Fetching movie with media key: [ 'fr-FR', 'movie', '1087192' ]
======Fetching movie with media key: [ 'fr-FR', 'movie', '1087192' ]
======Fetched movie with id: 1087192 in 588.1146249999874 ms
======Fetched movie with id: 1087192 in 587.7401250000112 ms
======Fetched movie with id: 1087192 in 572.4265410000226 ms

With :
export const getMovie = cache(({
    locale,
    id,
} : {
    locale: string;
    id: number;
}) => {
    return unstable_cache(
        async () => {
            const t0 = performance.now();
            console.log('======Fetching movie with media key:', mediaKeys.detail({ locale: locale, id: id, type: 'movie' }));
            const supabase = await createClient(locale);
            const { data: film, error } = await supabase
                .from('media_movie')
                .select(`*`)
                .match({
                    'id': id,
                })
                .returns<MediaMovie[]>()
                .maybeSingle();
            const t1 = performance.now();
            console.log(`======Fetched movie with id: ${id} in ${t1 - t0} ms`);
            if (error) throw error;
            return film;
        },
        ['test'],
        {
            revalidate: MEDIA_REVALIDATE_TIME,
            tags: ['tmdb']
        }
    )();
});
Its called 3 times (layout, page and generateMetadata) but after its well cached but the first time is broken idk
hmm looks strange, sorry idk either
@joulev hmm looks strange, sorry idk either
California pilchardOP
Wait Ive test something :
const getTest = cache(
  async () => {
    console.log('getTest called');
    await new Promise((resolve) => setTimeout(resolve, 1000));
    return 'Test data';
  },
  { tags: [`settings`], revalidate: 10 },
);

WHen the function doesnt have params its well cached, but with this :
const getTest = cache(
  async ({ locale, id }: { locale: string; id: number }) => {
    console.log('getTest called');
    await new Promise((resolve) => setTimeout(resolve, 1000));
    return 'Test data';
  },
  { tags: [`settings`], revalidate: 10 },
);

isnt cached well
waiiiiiiiiit I think its working
If I do :
export const getMovie = cache(
    async (locale: string, id: number) => {

instead of :
export const getMovie = cache(
    async ({ locale, id } : { locale: string; id: number}) => {
California pilchardOP
SO I guess its cache() from react which isnt able to cache using object in params ?
no idea man
methinks it has something to do with ===

objects cannot be compared with === but string and number can
California pilchardOP
Okay I found why (probably) (from https://github.com/facebook/react/issues/31390) :
the objet isnt in the same instance when we call getMovie(object) so the cache think its a different one