Client side cache best practices
Hi!
Finally getting my hands on TanStack and I love it so far. One question I have though is regarding cache best practices when it comes to invalidate vs manually update it.
Say I have a simple CRUD api:
The main thing from this API is that some queries say
DELETE /api/services/[service-id]
(DELETE_ SERVICE) will have some impact on the response of others e.g GET /api/hospitals/[hospital-id]/services
(HOSPITAL_SERVICES) or GET /api/hospitals/[hospital-id]
(HOSPITAL).
When using useMutation
for the DELETE_SERVICE
, I am not sure if manually updating the cache for the keys associated with HOSPITAL_SERVICES
and HOSPITAL
is a good practice.
For the HOSPITAL_SERVICES
cache I would need to loop through the array of {serviceId, serviceName}
and remove the correct one. For the HOSPITAL
cache I would need to decrement serviceCount
by one.
And to some extent one could argue that once I have the initial state of my app, then I could always rely on manually updating the cache and never actually refetc the data from the server. So my main question is to which extent is it considered good or bad practice? When invalidating cache is better over manually updating it?
Another related question: is updating the cache "thread safe" (or async context is maybe more precise)? Not sure if it really means something in JS but basically if the same mutation is called twice and the onSuccess
of both tries to decrease the cached serviceCount
, isn't my state going to be corrupted (e,g showing 6 instead of 5 for instance)?6 Replies
afraid-scarletOP•3mo ago
Last question is regarding query keys, how to best organize them? I know you can put structures into it and have some sort of hierarchy but when things are a little more coupled I don't really know what's best. For instance is there any pros/cons of doing this:
over
Thanks a lot for the help 🙏
Hey, bumping this, if anyone could help that'd be really appreciated
foreign-sapphire•3mo ago
Here some useful reads about best practices and patters of keys https://tkdodo.eu/blog/effective-react-query-keys
as for caching, ideally you want to invalidate every time there a change, to make sure users sees actual server state (eg if another user deleted a service you will never know if you only patched the cache)
The latency difference is barely noticeable in most cases but is much much easier than updating cache yourself over time.
Updating the cache right away with data from a response and also invalidating the query for update with fresh data is common too (in case of lists changes beside you own updates for example)
Effective React Query Keys
Learn how to structure React Query Keys effectively as your App grows
afraid-scarletOP•3mo ago
Thansks for your answer. I definitely gave this blog post a read.
I am concerned a bit with manually updating the cache. It looks like it is almost going to be re-implementing the backend logic to the frontend. Is it idiomatic in tanstack query?
Also it couples different unrelated features like "services" and "hospitals". The services feature now needs to know all the other features that track data which could depend on a specific service and invalidate its cache. How is it done in practice when you have way more than 2 features?
Cc @TkDodo 🔮 , sorry for the direct tag. I have not found this topic to he addressed a lot in your learning resources. I would love to hear your thoughts on that 🙏
foreign-sapphire•3mo ago
Take a look at the options of invalidateQueries, more often than not invalidating all the active queries after a mutation is a good tradeoff of performance and complexity
https://tanstack.com/query/latest/docs/reference/QueryClient#queryclientinvalidatequeries
foreign-sapphire•3mo ago
The idiomatic approach would be using query invalidation. Manual updates to the cache avoid another round-trip, but it means re-implementing server logic on the client.
afraid-scarletOP•3mo ago
Hey thanks for the answer, makes sense. I'm a bit concerned about this logic duplication between frontend and backend.
I think that's certainly where the dev has to draw the line and sometine simply invalidate the query and let the frontend simply refetch the data