React.cache vs unstable_cache?
Answered
Peterbald posted this in #help-forum
PeterbaldOP
I was previously using React.cache for a lot of one-time serverside actions but realized that I want to revalidate them later. I came across next's unstable_cache and it seems perfect.
But now I'm wondering why next's cache is unstable when React also offers a "stable" cache of its own? Are there any fundamental differences between the two
But now I'm wondering why next's cache is unstable when React also offers a "stable" cache of its own? Are there any fundamental differences between the two
Answered by Jboncz
Nextjs cache deduplicates by persisting the response on disk or in memory, where as react cache deduplicates the request... if that makes sense.
230 Replies
@Peterbald I was previously using React.cache for a lot of one-time serverside actions but realized that I want to revalidate them later. I came across next's unstable_cache and it seems perfect.
But now I'm wondering why next's cache is unstable when React also offers a "stable" cache of its own? Are there any fundamental differences between the two
They both of their pros and cons.... unstable is a misnomer, its labeled as unstable as its not finalized and is subject to change, BUT
Its not unstable as in, its buggy, I havent run into any real bugs with it.
Warning: This API is unstable and may change in the future. We will provide migration documentation and codemods, if needed, as this API stabilizes.Its not unstable as in, its buggy, I havent run into any real bugs with it.
@Jboncz They both of their pros and cons.... unstable is a misnomer, its labeled as unstable as its not finalized and is subject to change, BUT Warning: This API is unstable and may change in the future. We will provide migration documentation and codemods, if needed, as this API stabilizes.
Its not unstable as in, its buggy, I havent run into any real bugs with it.
PeterbaldOP
what are the pros and cons of each?
like what is the difference outside of being able to use revalidateTag with it
Nextjs cache deduplicates by persisting the response on disk or in memory, where as react cache deduplicates the request... if that makes sense.
Answer
https://stackoverflow.com/questions/78176223/whats-the-difference-between-react-18s-new-cache-and-next-js-deduping
this is a really good stack overflow answer, has a bit more context
this is a really good stack overflow answer, has a bit more context
@riský wraps his expensive fetches in unstable cache and react cache to get best of both worlds 😄
@Jboncz Nextjs cache deduplicates by persisting the response on disk or in memory, where as react cache deduplicates the request... if that makes sense.
PeterbaldOP
ah, I see. So unstable_cache doesn't get reset per new request
is that correct
Correct, you typically set a time limit, and gets reset after that time limit. So me and you visitng page x thats using unstable cache get the same data till we hit the page/function after the revalidation time has passed
export async function eventManagementGetRecentTickets() {
const sqlPool = await sql.connect(eventmgmt_config);
const sqlRequest = new sql.Request(sqlPool);
const sqlQuery = `SELECT TOP (300) * FROM [IAMEM].[dbo].[iamevents] WHERE [status] like '%Ticket%' Order by [eId] desc`;
let queryResult = await sqlRequest.query(sqlQuery);
await sqlPool.close();
if (queryResult.recordset.length > 0) {
return queryResult;
}
return null;
}
export default async function Page() {
const tickets = await unstable_cache(eventManagementGetRecentTickets, [], { revalidate: 60, })()
return (
<div className="m-2 bg-paper rounded-md">
<div className='p-2'>
{tickets &&
<GenericTableV2 data={tickets} />
}
</div>
</div>
)
};Heres a simple example.
If me and you go to the page, we are getting the data from the web server not the sql database, once the data is 60 seconds old... the next time someone hits the page or that function gets called, it will fetch new data and store it in memory
@Jboncz <@657067112434499595> wraps his expensive fetches in unstable cache and react cache to get best of both worlds 😄
PeterbaldOP
is there an example of this? I kinda want to use per-request cache with a revalidateTag option
or is that not possible
tysm btw
that was the solution
Yeah lemme go look at his repo again
You can force unstable cache to revalidate by passing in a new keyParts
Unstable cache is pretty magical.
tbh
😄
revalidate: The number of seconds after which the cache should be revalidated. Omit or pass false to cache indefinitely or until matching revalidateTag() or revalidatePath() methods are called.PeterbaldOP
ok so I'm getting some strange behaviour
where functions cached with
React.cache are reset after using revalidateTagi want to have some functions that are cached per request... but revalidateTag revalidates all of them it seems?
React.cache is only for one request/render
unstable_cache is persistent across requests
PeterbaldOP
yeah i learnt about that
React.cache is being refreshed when I call revalidateTag in one of my server actions though
is that normal behaviour
i cant remember what react cache for client side does tho, but considineg revalidateTag on server action does lots, i assume it clears
PeterbaldOP
i have a react cache on serverside
it's being cleared even though it's the same request, i just called revalidateTag and all the react cache functions ran again
@Peterbald it's being cleared even though it's the same request, i just called revalidateTag and all the react cache functions ran again
Havana
The thing with react cache is that it doesn't persist forever, it has a lifecycle, and whenever you refresh the page it will clear that specific cache out
PeterbaldOP
yes that's what I want
for certain functions
Havana
okay, so whats the issue 😄
PeterbaldOP
calling revalidateTag clears that specific cache out
on a server action
somehow
Havana
That is something unusual, it only needs to work for the unstable cache
There have been reports and discussions about revalidateTag and revalidatePath unintentionally clearing or affecting caches beyond their intended scope, including those related to React.cache.Havana
Why do you even need to revalidate it anyways?
If you know that this will clear out on refresh anyways
@Havana Why do you even need to revalidate it anyways?
PeterbaldOP
i have some functions that need to be cached per request, and some functions that need to be cached for all requests
Havana
yeah, so divide them by react cache and unstable cache
😄
Or you are saying that revalidating the unstable cache also revalidates the react one
Havana
😂
wow, that is actually crazy
PeterbaldOP
😭
so what should I do
this is sad
i will just stop using unstable cache and force the user to completely refresh the page for updated data
ok tbh, I don't know where and how the react cache is being cleared, but I just know that the 2 don't work in harmony right now
it was working before I used unstable cache
@Peterbald it was working before I used unstable cache
Havana
maybe that causes the issue
I never faced things like that in my life
You know, what if you scope out the react cache?
Make it work on the client side, and the unstable cache leave on the server side
Make it work on the client side, and the unstable cache leave on the server side
It can work
PeterbaldOP
bro wait
this is actually the weirdest behaviour
i've ever seen
@Peterbald i've ever seen
Havana
Try to scope it out, should work
PeterbaldOP
no like
the function in react.cache runs twice back-to-back
first weird behaviour
Havana
Yep
PeterbaldOP
it wasn't happening on any other pages
Havana
But try scoping out, since the revalidation happens on server side, it shouldnt affect the react cache, even if its a bug
Wrap component with this react cache, and in the parent use the unstable cache
The child should be client
PeterbaldOP
react cache was for server side state
for a request
Havana
Server side state?
or a value
@Havana Server side state?
PeterbaldOP
like state management
for server side
for 1 request
it's the equivalent of setting an object like
req.customData in any other server frameworkHavana
You can try using unstable cache with a unique key, for example Date.now()
It will revalidate on page reload
It will revalidate on page reload
instead of using react cache
just don't set any revalidate time for it
PeterbaldOP
i need it as per-request
and there isn't any reliable id
i can provide
i'll have to pass something down somehow to other pages
Havana
Since its a cache that will be cleared out on a refresh you can just create any unique key to it, doesn't matter, even crypto.randomUUID()
@Havana Since its a cache that will be cleared out on a refresh you can just create any unique key to it, doesn't matter, even crypto.randomUUID()
PeterbaldOP
but how do I get that unique key
across different pages
from the same request
Havana
But you said only this page doesn't work with the react cache
the others you can leave as is
the unstable cache, the one you actually store and revalidate when needed, you don't touch
You only replace the react cache, the one time cache, with another unstable cache
@Havana But you said only this page doesn't work with the react cache
PeterbaldOP
it's behaving strangely
and I can't even figure out how
Havana
Maybe its not about react cache, yeah 😄
maybe some of the page's code is making it do weird things
PeterbaldOP
like is it because i'm using <Link>'s to navigate
Havana
ohhhhh
pass prefetch = {false} to the link
prop
and tell me if it solved the issue
PeterbaldOP
why would prefetch resolve the issue
it only prefetches once
Havana
Try that
PeterbaldOP
prefetch is false in dev mode
by default
so it cannot be the issue
Havana
Oh, in dev
okay, nvm
PeterbaldOP
im thinking maybe it's because of the page
do rscs run once?
like
Havana
Yes? 😄
PeterbaldOP
if you do <Link> navigate to a different page, and <Link> to navigate back
what does the rsc do
for that page
does it re-run?
but that wouldn't make a lot of sense either
Havana
It doesn't
PeterbaldOP
tbh i can completely stop using react.cache
if there was a way to store a javascript object on the singular request object
Havana
this happens when you load the page, or go back after you clicked the link?
@Havana this happens when you load the page, or go back after you clicked the link?
PeterbaldOP
yes, and it happens randomly
sometimes it the cache dies
sometimes the cache works
all im doing is navigating back and forth
Havana
And it doesn't work because you use revalidate stuff inside that same page?
PeterbaldOP
i commented out the revalidate stuff
and somehow... still doesn't work?
i commented out all the imports frmo next/cache
in my entire app
and I can assure u the cached function runs on the server
Havana
Well, I just read that when navigating between pages, using Link, it doesn't clear the cache out
The react cache
PeterbaldOP
it does!
Havana
Well this is crazy
PeterbaldOP
but i thought it's a single request
since <Link>'s are just doing window.history.pushState
Havana
it is
When navigating it's not supposed to clear this out
PeterbaldOP
wait are there extra requests to rscs when navigating to a new page?
that would... make sense? if it's serverside dynamic data
and react cache is per request... so that's technically a new instance
Havana
yes, there are
PeterbaldOP
ahhh
i think i kind of undestand
what im doing wrong
Havana
well if for example the server page requires a fresh data, if its not cached or static or etc, it refetches it
PeterbaldOP
it's a bit weird though
Havana
But in your case it is cached...
PeterbaldOP
OOOOOHHHH
i have fresh data + cached data
that's why the cached function is running again too
Havana
well, thats why
PeterbaldOP
yeahhh
Havana
Now you have to take care of it
PeterbaldOP
ok
Havana
Gl with that
PeterbaldOP
ill try to figure something out 😭
Havana
Trust me, its the easier part 😄
the hardest was to figure out why
PeterbaldOP
is there a way to send a prop to a rsc when data is refetched (from the client)
Havana
No, you can't wrap OR import rsc from client
You have to do the opposite
Or do it all SSR
And then pass the data to client if needed
PeterbaldOP
like there's a lot of
?_rsc=.... requestsis it possible to configure some kind of data to be passed
Havana
wdym, like whitelisting data?
PeterbaldOP
nvm
i haven't slept in like 30 hours
Havana
😄
PeterbaldOP
i think it's about time
Havana
Glad we figured out the issue though
PeterbaldOP
yeah, tbh i didn't fully understand rsc
@Peterbald yeah, tbh i didn't fully understand rsc
Havana
will help where I can
PeterbaldOP
yee tysm
ohhhhh i know how to solve my state issue
is there a way to cache a function that's dependent on a serverside cookie
as long as the cookie does not change
the function returns the same result
Havana
yes
you can access cookies from serverside using cookies import
@Havana you can access cookies from serverside using cookies import
PeterbaldOP
but caching?
Havana
obv using unstable cache
yes
PeterbaldOP
ok
so like
React.cache(() => {
/* cookie */
return unstable_cache(
() => {}
[cookie]
)();
});smth like that
should work
Havana
why double cache?
only unstable
return unstable_cache(() => function(), [
revalidate: 60 * 60 * 20,
tags: ["tags you want(not required)"],
});
unique-cookie], {revalidate: 60 * 60 * 20,
tags: ["tags you want(not required)"],
});
something like this
@Havana why double cache?
PeterbaldOP
idk i just like caching
Havana
😄
@Havana return unstable_cache(() => function(), [`unique-cookie`], {
revalidate: 60 * 60 * 20,
tags: ["tags you want(not required)"],
});
PeterbaldOP
where would I get this unique-cookie
it's dynamic
Havana
import { cookies } from "next/headers";
then cookies().get("key")?.value
PeterbaldOP
so like
// cached_functions.ts
const getData = async () => {
const cookieList = cookies();
return unstable_cache(
() => function(),
[cookieList.get("key")?.value]
)();
}Havana
yeah, but get the value before the caching
just a nice practice
PeterbaldOP
wdym get the value before caching
Havana
const cookieValue = cookieList.get("key")?.value
PeterbaldOP
ah yeah
Havana
😄
thats the way
PeterbaldOP
i am just typing it out
yeah
ok
Havana
ye
You will also need to make sure if the cookie value exists, if not set the key to 'default'
const cookieValue = cookieList.get("key")?.value || "default";PeterbaldOP
i got a middleware to make sure that cookie exists
it's chill
Havana
oh, so user doesn't even get on the page if he doesn't have the cookie?
Good one
lol i come back here with so many messages and you have worked out issue right?
Havana
yep
@riský lol i come back here with so many messages and you have worked out issue right?
PeterbaldOP
yeah i just forgot rsc is refetched if there's dynamic data
and the cached functions rerun
beacuse it's no longer the same request