-
-
Notifications
You must be signed in to change notification settings - Fork 3.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
queryFn erroneously called in useSuspenseQuery dependent on serial prefetch #8828
Comments
when You have to make sure that all promises are already started in the RSC when you render the client component. For dependent queries, this isn’t really possible because you don’t even know the queryKey yet. So I think yo need to |
The first time However, I think you're right that this is a timing issue. What I'm expecting to happen is this:
But what's happening instead is that as soon as the first prefetch call completes, the component inside the One solution would be for me to combine the two prefetch queries into one by moving the serial request logic into // code in the RSC to perform two serial fetch operations
void queryClient
.fetchQuery({
queryKey: ["favoritePokemonIdAndPokemonData"],
queryFn: () =>
// simulate database call to look up the user's favorite Pokemon
new Promise<number>((resolve) =>
setTimeout(() => resolve(Math.ceil(Math.random() * 100)), 500)
).then((favoritePokemonId) => {
return {
favoritePokemonId,
pokemonData: queryClient.prefetchQuery(getPokemonOptions(favoritePokemonId));
};
})
}) That's not ideal, though. It means that the prefetch timing would be dictating what the data looks like when it's consumed. Another solution would be for me to create my own context to provide the promise returned by TanStack Query's fetch functions, and then But I think it would be better for TanStack Query to offer first-class support for serial prefetch queries. One way to do that would be with a function that does the promise-passing described above; let's call it // code in the RSC to perform two serial fetch operations
void queryClient.suspendUntil(async () => {
const favoritePokemonId = await queryClient.fetchQuery({
queryKey: ["favoritePokemonId"],
queryFn: () =>
// simulate database call to look up the user's favorite Pokemon
new Promise<number>((resolve) =>
setTimeout(() => resolve(Math.ceil(Math.random() * 100)), 500)
),
})
await queryClient.prefetchQuery(getPokemonOptions(favoritePokemonId));
}) |
By the way, the TanStack Query docs on Streaming with Server Components make it sound like this streaming multiple prefetches should "just work":
And later in that doc:
So I hope you can understand my confusion here. The doc says "prefetches" plural, but in practice the streaming-while-rendering pattern only works with a single non-async prefetch. |
that’s not true. You can prefetch multiple things in parallel, like I don’t think we’ve ever really thought about dependent prefetching with streaming, which is why I haven’t closed this issue already. Right now, I would just say it’s not supported, don’t do it. Not sure what @Ephem’s take on this is, but I’d be curious :) |
I agree with the conclusion that we simply don't support this right now, but I do think we should if we can (I've also run into these cases and have had to work around them, like falling back to The way I would see a solution for this particular problem working is by some form of |
A readHeaders().then(/* prefetch based on headers... */) |
Describe the bug
I've been struggling to get the Suspense prefetch-with-streaming pattern working in my app when there are multiple prefetch queries (because one prefetch request depends on the result of the other).
The problem is that the
queryFn
gets called for the seconduseSuspenseQuery
call during SSR. For example:This code causes SSR to fail with the error
Second queryFn in pokemon-info should never be called
.Interestingly, if you stub out the
queryFn
with a no-op function, the code seems to work, with the seconduseSuspenseQuery
returning data immediately. That suggests that theSuspense
boundary is correctly blocking the component with theuseSuspenseQuery
from rendering until the prefetch has completed, but then it's incorrectly trying to fetch the prefetched data again, even withstaleTime: Infinity
.Your minimal, reproducible example
https://codesandbox.io/p/devbox/dreamy-sky-znq6jh?workspaceId=ws_CZBXqWgnzWZNdzjDui2die
Steps to reproduce
await
to allow for streaminguseSuspenseQuery
for all prefetched data from a component inside of a<Suspense>
boundaryExpected behavior
The
clientFn
provided touseSuspenseQuery
should never be called during SSR, because the hook is for loading prefetched data. (It should only be called on the client after the data is invalidated.)How often does this bug happen?
Every time
Platform
macOS, but reproducible in CodeSandbox. Reproducible under Next.js 15 w/ React 19, and Next.js 14 w/ React 18.3.
TanStack Query version
5.68.0
The text was updated successfully, but these errors were encountered: