Skip to content

QueryObserver and useQuery behavior when present in same render cycle but different components #6156

@KartheekJavvaji

Description

@KartheekJavvaji

Describe the bug

I was making use of QueryObserver to subscribe to a particular query updates, to show some metadata of the fetched data in a different part of the application. I have come across a strange behavior where the placement of the QueryObserver in the 'react component tree' varies the outcome.

If the QueryObserver is placed at a higher level in the 'react component tree' when compared to the target useQuery, then it works as expected.

But the QueryObserver is placed at a lower level in the tree (and that entire sub-tree gets rendered together at once), then the query is executed with no queryFn and we get an error saying missing queryFn. This even makes the useQuery get the same result.

Once some data is populated for the queryKey, the behavior matches exactly how QueryObserver behaves when placed at a higher level in the tree. However, if staleTime and cacheTime for the query are set as 0, this happens every time.

Your minimal, reproducible example

https://codesandbox.io/p/sandbox/react-query-observer-race-condition-kx68cl?file=%2Fsrc%2FRoutes.tsx%3A10%2C13

Steps to reproduce

  1. I have created 3 variants in the code-sandbox example - ItemsVariant1, ItemsVariant2, and ItemsVariant3.
  2. ItemVariant1 has the QueryObserver at a higher level in the tree than the useQuery.
  3. ItemVariant2 has the QueryObserver at a lower level in the tree than the useQuery and ItemVariant3 is exactly the same as ItemVariant2, but it subscribes to QueryObserver inside a setTimeout with 0 timeout.
  4. We can see the console.log (or even reactQueryDevtools) for the issue.

Expected behavior

I have gone through the documentation and other closed GitHub issues and understood that QueryObserver and useQuery are not much different at their core, as useQuery internally uses QueryObserver. I am unable to understand where QueryObserver will be useful for us given the above behavior.

  1. What is the recommended way of getting the query data at another place than the place where useQuery is used? QueryCache doesn't give real-time updates. Should we rely on something like useIsFetching and then imperatively get data from queryCache?
  2. Or should it be through reactContext as mentioned in https://tkdodo.eu/blog/react-query-and-react-context.
    a. But if the component where we want to use the data is not at a lower level of the same
    sub-tree as useQuery, then we would have a context at some common higher level with
    a state in it. And we will be setting the entire query state as we would also need
    variables such as isFetching and others. This is slightly deviating from the solution
    discussed in the blog and hence I tried using QueryObserver over here.
  3. Is QueryObserver only supposed to be used internally or for building our own flavor of useQuery?

How often does this bug happen?

Every time

Screenshots or Videos

reactQueryObserver.mp4

Platform

  • MacOS
  • Chrome

Tanstack Query adapter

None

TanStack Query version

5.32.6

TypeScript version

No response

Additional context

No response

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions