Why does adding an observer to react-query cause it to ignore its `enabled` property?

Viewed 1966

Update: I've now filed this as an issue over on react-query's Github, you should probably follow it there.

I have a pretty straightforward useQuery:

const refreshable = false // hard coded for the sake of example
const tokenQuery = useQuery('refresh-token', refreshQueryFn, {
  enabled: refreshable,
  refetchInterval: 1000 * 30,
  refetchIntervalInBackground: true,
})

If this is stand-alone then no problems. Everything initialises, and unless refreshable is set true then it lies dormant.

However, in the same hook I added an observer...

useEffect(() => {
  // Create an observer to watch the query and update its result into state
  const observer = new QueryObserver(queryClient, {
    queryKey: 'refresh-token',
  })
  const unsubscribe = observer.subscribe((queryResult) => {
    console.log(
      'Do something with the token!'
      queryResult.data
    )
  })

  // Clean up the subscription when the component unmounts
  return () => {
    unsubscribe()
  }
}, [token, queryClient])

Attaching the observer causes a fetch (and failure, and multiple retries) to happen irrespective of enabled, which I don't think should happen.

Can anyone explain why this happens, before I raise an issue on react-query?

1 Answers

under the hood, useQuery creates a QueryObserver with the options you pass to it. So after the userQuery, you'll have one observer with enabled: false, which will give you a disabled query.

Now enabled is a per-observer property. It is totally legit to have one useQuery instance that is enabled while having another with the same queryKey that is disabled.

And this is basically what you are doing: When you manually create the new QueryObserver, you are not passing enabled: false to it, so you create a second observer that is enabled, which will then run the query.

So passing refreshable to the new Oberver's enabled option should solve it:

const observer = new QueryObserver(queryClient, {
  queryKey: 'refresh-token',
  enabled: refreshable,
})
Related