Techniques for reducing request waterfalls for dependent queries in loaders
I'm using TanStack Router, Query, and Start (though I think Start is irrelevant for this Q)
I'm wondering about loaders that are run for client-side transitions that would be run more effectively on the server-side. Consider the following:
I can configure this quite cleanly to run in SSR (server-side rendering) on the initial page load via this pattern in the docs:
but if I'm navigating to this page via CSR (client-side rendering) this loader will run on the client, which adds extra latency in between dependent queries:
I recognize that both cases involve dependent queries (eg. query 2 can't run until we finish query 1), but I was wondering if there was a solution here for the added server-roundtrip latency between the queries in the CSR case? In some scenarios this may be the dominant latency driver.
18 Replies
like-goldOPβ’2w ago
Intuitively, what would be neat is if I could say "even on a client-side navigation, this loader should always run on the server", with the same special hydration/streaming hookups under the hood as the SSR-query-integration, so if I do things like
ensureQueryData
on the server and have it pipe through to the client automagically.
One potential complication here is that the client may have queryClient
state that would've instantly resolved on the client but has to be recalculated from scartch in SSR. I'm sure I'm missing some more facets, which is why I wanted to pick the brains of the smarties here and see πgenetic-orangeβ’2w ago
put all this in a server function to let it run on the server always
like-goldOPβ’2w ago
Hi @Manuel Schiller , thanks for the quick reply π
This came to mind, but the issue then is that now I'm returning a large monolithic response, vs having small modular
This came to mind, but the issue then is that now I'm returning a large monolithic response, vs having small modular
queries
which can be reused/deduped.
For instance say I'm fetching many posts and many authors for those posts, ideally I can just rely on queryClient
to dedupe the authorStats
queries. If I do one monolithic response then I need to consider this and dedupe manually case-by-case, vs some way with queryClient
would be super ideal.rare-sapphireβ’2w ago
Does TanStack DB have a place here?
like-goldOPβ’2w ago
I can imagine a middleground where I return a dehydrated queryClient state and hydrate it client-side in my loader, but that's what led to me wondering if there's a pattern here that can be generalized and exposed in a cleaner way, since dependent queries feels like a common usecase! π
rare-sapphireβ’2w ago
Anywhere there is duplicated data between say, REST requests, normalization can play a big role
like-goldOPβ’7d ago
Admittedly in my list of the
TanStack Infinity Guantlet
β’ that I'm utilizing, I haven't touched DB yet. I can investigate to see if there's a cleaner way through there. Will report back if I find anything π«‘
Quick loopback here since I promised an update, not expecting a response from the team π
Poked around with TanStack DB. I was candidly surprised a bit that some of the flows I'd consider common not being as accessible. For instance, the core queryFn having to return the full state of the collection was really confusing, and having to immediately jump into the advanced flows which are deemed "an escape hatch" makes me wonder if I'm using the wrong tool. It seems these "escape hatches" are what I'd need for nearly all my collections based on how my app works; I expect this to only improve as the library trends towards a stable 1.0, but wanted to mention nonetheless.
More on-topic, I can see how TanstackDB helps to denorm things, but for my top-level-Q we ultimately still have the fundamental tension between
1. client wants modular queries to reuse in different spots
2. server wants dependent queries to be run in a single method call to avoid roundtrips
As I mentioned in my OP, this feels great during SSR but for proceeding CSRs it doesn't. I still think a simple option to force-ssr loaders with built-inhydration may be a subtly low-hanging-fruit solution here.
I appreciate the brains batting the idea back and forth with me though. Thanks a lot π π«‘genetic-orangeβ’7d ago
cc @Kyle Mathews maybe you can help out here?
secure-lavenderβ’7d ago
advanced flowsYou're referring to direct writes? The docs page? Refetching the whole state of the collection is how Query works by default so we're just copying that. That's simple and performant. It's of course normal for many to do advanced things which is why the direct write apis are there β we could tone down the "advanced" and "escape hatch" language if people think these are more normal than advanced APIs. But they are inherently much more error prone than just refetching so my general feel is people should just refetch until they obviously can't. Databases can do an enormous number of reads so most apps are fine until they hit pretty serious scale. And refetching Just Worksβ’ w/o any work which is great early on (granted, you might already at scale β but this is the argument for how the docs are written). What are some dependent queries your app has? How big of issues is roundtrips?
like-goldOPβ’7d ago
direct writes/the docs pagesYup! I can give a simple example, I was looking at using TanStack DB for a "Posts feed" on my homepage. For this I'm currently using a "hot posts" infinite query. My first intuition was to use a "posts"-typed collection and then have a query on top of that which sorts by Hot, but then I realized I can't exactly have all posts loaded to the client, that'd be a lot of posts π I can amend this by doing a "hot posts"-typed collection, which is populated by the first page of hot posts specifically, but now 1. I have un-denormalized my data, slightly defeating the purpose 2. I have to manually handle the "infinite" part of the query (DB supports pagination on its tables, but the underlying query collection logic doesn't support fetching via pagination AFAICT The best solution by far seems to be hand-rigging up useInfiniteQuery with manual writes to the DB/collection, which isn't terrible, but again it feels like I'm fighting the tools a bit for something which could otherwise be smooth. Esp given the tool emphasizes differential data flow, it feels like this type of dynamic should be more first-class rather than in the advanced/escape hatch areas. Perhaps I'm completely missing the mental model for how this should work or how to use it; happy to be schooled here if so π π§ Ignoring that, I could see DB helping me with the dependent queries like this: 1. I have my collection of posts, which materialize a view of authors, which are deduped 2. those deduped authors' data can now be fetched en bulk Btw again this is a scenario which likely leads to me reaching for the direct-write API, since otherwise I'm having a queryFn which needs a closure/context from the other DB's state, and refetches all authors each time rather than only new ones as-needed
secure-lavenderβ’7d ago
you don't have to denormalize. I think for something like this I'd just poll every so often for updates and that'd be fine β especially if you maintain the list in redis or something like that.
it does depend though how many posts & authors you have
it might be reasonable to just load all of them
and then normalized is easy
secure-lavenderβ’7d ago
GitHub
Partitioned collections Β· Issue #315 Β· TanStack/db
A very common use case, and question, is how to handle collections where you don't want to download all of it. Such as issues in an issue tracker, downloading by project/status/createdData etc....
secure-lavenderβ’7d ago
will make it so you can lazy load authors
like-goldOPβ’7d ago
The intention is an infinite query. Think a twitter timeline-- obviously my humble app isn't at that scale, but you can hopefully see how loading and refetching all tweets just to show the user's Recent feed is a bit intense!
secure-lavenderβ’7d ago
yeah for sure! We're also working on https://github.com/TanStack/db/issues/343
GitHub
Paginated / Infinite Collections Β· Issue #343 Β· TanStack/db
A common request we are receiving is to lazily load data into a "query collection" using the infinite query pattern. We need to consider how to support this in a way that is then useable ...
secure-lavenderβ’7d ago
as you're an obvious infinite query scenario
so infinite feed for the main posts & partitioned for all the other related data to keep things tight and normalized sounds pretty good
like-goldOPβ’7d ago
Thankful I had the foresight to say:
I expect this to only improve as the library trends towards a stable 1.0I figured the TanStack gigabrains would already have plenty cooking to address my usecases, glad to see the specific issues I can track π Appreciate the engagement on my feedback, I'll def keep tracking these issues. And excited more generally for TanStack DB to continue maturing π«‘
secure-lavenderβ’7d ago
cc @samwillis who's the one actually working on these π