ensure vs prefetch query in deferred data loading
I'm trying to understand the difference between
ensureQueryData and prefetchQueryData, esepcially in the context of deferred loading.
From the tanstack router docs:
Then in the component:
I get why we don't await the prefetch query, since we want to let it resolve in a <Suspense /> block.
But from the docs it seems like the main diff. between the two is that prefetch will never throw, and ensureQueryData will prefer to serve cached data.
But for instance, why can't both use prefetch or both use ensure?16 Replies
conscious-sapphire•8mo ago
This is the best explanation of the differences so far https://discord.com/channels/719702312431386674/1003327027849474198/1313780863430819871
automatic-azureOP•8mo ago
Super helpful, thank you!
grumpy-cyan•8mo ago
FYI this question comes up so often that I'm thinking about depreciating all the methods and just do
queryClient.query(...) with some options. The difference are so minor that it usually doesn't matter
Also, when you use suspense, there is really no reason to await anything in the route loaders. Just kick off all things in parallel and let the components render and suspend if data isn't ready yetconscious-sapphire•8mo ago
You mean the child suspense boundaries, not the auto wrapped suspense at route level?
grumpy-cyan•8mo ago
I mean all of them
Even if you don't add your own suspense boundary, router would render the component and then useSuspenseQuery would just immediately throw to the router suspense boundary again
conscious-sapphire•8mo ago
So I guess by that definition "critical data" is just something you suspend on immediately, and "non critical" data is stuff with its own sub boundary and loading fallback
grumpy-cyan•8mo ago
why woudl we even need to differentiate between the two when using react-query?
the code shown above won't even work because this:
is outside the Suspense bounary so it will go to the router suspense boundary anyway ...
I would see it like that:
and then in the component:
the thing is: once you kick off fetching in the route loader, it's all good. Suspense won't waterfall anymore. You can then compose
useSuspenseQuery however you want. If you want to wait for everything to reveal at the same time, just do:
that's the same as awaiting them both in the route loader - because they'll both hit the router suspense boundary. Or am I wrong 😅 ?
@Manuel Schiller tell me I'm wrong
like, what's the point in awaiting anything in a route loader if we don't intend to ever useLoaderData ...
I guess maybe pendingMs and pendingMinMsdon't come into play then? Because the loaders are basically synchronous if you don't await anything in them 🤔useful-bronze•8mo ago
there are cases in Start (or any SSR setup) where you would want to await in the loader
recently saw one example where the SSR response needed to contain cookie header that was set by calling a server function using query
if you do not await the loader, that cookie will not make it through to the client
grumpy-cyan•8mo ago
that was set by calling a server function using queryhmm, queries shouldn't have such side-effects ?
useful-bronze•8mo ago
well sometimes they do ...
when you call a server function and it sets a header, then the SSR response will inherit that header
but only if you wait for it
grumpy-cyan•8mo ago
okay but for pure non-SSR situations?
useful-bronze•8mo ago
there are other examples, e.g. reading the query result in e.g. meta(), also needs to happen before the response is built
i can only think of SSR situations right now
grumpy-cyan•8mo ago
yeah sure, if you need the result somewhere, you need to await; same if you want to prefetch conditional queries
useful-bronze•8mo ago
but TBH my head is quite SSR right now. it totally shifted from SPA to SSR in the last months 😄
not because I prefer SSR
just because of working on it ...
grumpy-cyan•8mo ago
just to add to that: I thought that if you trigger a prefetch on the server without awaiting, the component would render on the server and the
useSuspenseQueryCall there would then also suspend on the server . So why does awaiting in the loader matter?
also this seems magical ... too magical maybe ? If setting / forwarding the header were explicit, you'd know that you have to await it...useful-bronze•8mo ago
you can only set a response cookie before you finished sending the headers. but useSuspenseQuery (and thus the "response" of the server function) kicks in after the headers were already sent off
yes, I agree. setting the header inside the server function is already explicit, but the receiving part is not explicitly forwarding