0

I see that Tanstack Query supports parallel queries in a certain way that is dynamic, per this page: https://tanstack.com/query/latest/docs/framework/react/guides/parallel-queries#:~:text=each%20useSuspenseQuery%20instance.-,Dynamic%20Parallel%20Queries%20with%20useQueries,-If%20the%20number

In the example they provide, useQueries() hook is passed an array that is a prop of the component, so it is dynamic up to the point that the component is rendered and passed its props.

I have a situation where the number of parallel calls depends on the results of the previous batch of parallel calls. We are calling an endpoint that returns data paginated, but we cannot specify the page length and it does not reveal the number of pages ahead of time. The final page has in indicator that it is last. We want to make a certain number of parallel calls to this endpoint (say 10), and, if none of the responses indicates that it is the last, make another set of 10 parallel calls and so on.

I'm curious if the 'dynamic' nature of Tanstack's useQueries() is such that as the array of queries passed to it changes, the code will re-run any queries based on keys it's seen before. Taking their sample code of

    queries: users.map((user) => {
      return {
        queryKey: ['user', user.id],
        queryFn: () => fetchUserById(user.id),
      }
    })

If user is in component state, and that state is updated so its original value of 3 array members has 3 more appended to it, will Tanstack see that the keys of the first 3 match and not re-run those queries, but only the new ones?

I realize this is not great architecture and if we had any control over this endpoint we would be changing it and not trying to paper over its shortcomings on the front end. We need to load all the pages before the user can interact because the endpoint does not offer sorting or searching, and returns its results in an unpredictable sequence.

1 Answer 1

0

will Tanstack see that the keys of the first 3 match and not re-run those queries, but only the new ones?

yes, it would. But regardless, I don’t think that’s what you’d want here. As you point out, not a great architecture, but using multiple queries where you need to update some state after the last request was made (probably in a useEffect ?) to trigger some more requests sounds ... not ideal.

what I would try is to just pack everything into one queryFn and treat the result as the single resource. There is no rule that prevents the queryFn to make more than one request - it’s just promises after all:

queryFn: async () => {
  const first10Results = await Promise.allSettled(/* make 10 requests here */)
  if hasMore(first10Results) {
   /* make 10 more parallel requests or whatever */
  }
}

this is pseudo code obviously, you probably need to make some sort of loop that always fires 10 requests until it had enough. But this should get the idea across: The queryFn can abstract away all the quirks of your API and basically “hide” that from the component lifecycle.

The drawback is of course that you don’t get each page cached separately, but given that you need to load all pages anyways before the user can interact, this shouldn’t be a big deal.

Sign up to request clarification or add additional context in comments.

2 Comments

Thanks for the ideas. The problem with 1 single queryFn I'm seeing is that some of the individual requests fail, and I'd want Tanstack to retry them. I think this is infrequent enough that we can live with rendering the partial results while any retries happen in the background.
Here's an idea: the array returned from useQueries is mapped so each element is passed to a component that checks for isFetched and when it is, calls a fn in its props to notify its parent of the data so the parent can determine whether to add more queries to the useQueries. The parent would be tracking a cursor of which pages have been requested (which could include pages beyond the end) and another to track the actual known highest page number

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.