query
query copied to clipboard
[vue-query] Callback for enabled does not provide query as parameter
Describe the bug
Since v5.48.0 and the changes in #7566 the enabled property for TanStack Query in general does accept a callback function, which provides the the query as argument.
Sadly this does not work with vue-query, as vue-query did already accept a getter since #6018, which does not provide the query. It technically is possible to return a function from the getter and that one will provide the query, but that does not fit the current types and docs. In addition it seems to run unnecessarily often, as you can see in my example repro.
Your minimal, reproducible example
https://stackblitz.com/edit/vitejs-vite-dt8byq?file=src%2FApp.vue
Steps to reproduce
- Open the console
- The parameter
outerQueryinundefined
Expected behavior
The parameter outerQuery to be the query
Tanstack Query adapter
vue-query
TanStack Query version
5.51.21
This would only work if we also change the query type to be optional.
Otherwise it's a chicken and the egg problem.
First time when enabled getter would be run, we do not have observer yet and query might also not exist.
This is just an idea, but I haven't had the time to verify its feasibility recently.
Perhaps we only need to add a length check here:
https://github.com/TanStack/query/blob/639363c769e866ad4f9f7eb87147814ec8cbcbf0/packages/vue-query/src/useBaseQuery.ts#L88-L90
if (
typeof clonedOptions.enabled === 'function' &&
clonedOptions.enabled.length === 0
) {
clonedOptions.enabled = clonedOptions.enabled()
}
However, I haven’t thoroughly explored how to reinforce the type definition issue yet.
I have looked into the proposed solution, and it does seem possible to detect whether the user is using the query parameter in the enabled callback to decide whether enabled should be handled inside @tanstack/vue-query or delegated to the implementation in @tanstack/core.
However, I believe this might cause some confusion for users.
For example:
const isEnabled = ref(false)
const { data } = useQuery({
queryKey: ['posts'],
queryFn: fetcher,
enabled() {
return isEnabled.value
}
})
In this case, the code will track changes to isEnabled, which is the current expected behavior.
But in the following example:
const isEnabled = ref(false)
const { data } = useQuery({
queryKey: ['posts'],
queryFn: fetcher,
enabled(query) {
console.log(query)
return isEnabled.value
}
})
This version will not track changes to isEnabled.
Since the presence of the query parameter causes the logic to be delegated to @tanstack/core, and the execution happens after Vue’s internal reactive dependencies have been collected, this means that enabled will no longer react to changes in isEnabled.
I think this difference in behavior could easily confuse users.
To reduce potential misunderstandings, I personally prefer to keep enabled in @tanstack/vue-query as a pure MaybeRefOrGetter<boolean | undefined>, to avoid introducing too much complexity.
This is just my personal opinion, if there is anything I might have overlooked, please feel free to let me know.
@Mini-ghost I ran into this issue precisely because this feature would be super useful for our use case, so just scrapping it in the Vue version isn't super satisfying.
Thinking about it more, it isn't super necessary for enabled to accept a getter because the same can easily be accomplished with a computed. Using your example:
const isEnabled = ref(false)
const { data } = useQuery({
queryKey: ['posts'],
queryFn: fetcher,
enabled: computed(() => {
return isEnabled.value
}
})
Removing the getter option would obviously be a breaking change, but it would keep the Vue version more in line with Tanstack Query for other frameworks.
@Jak-Ch-ll
I've updated #9276 to make it at least possible (from a type perspective) to "return a function from the getter, and that one will provide the query".
const { data } = useQuery({
queryKey: ['posts'],
queryFn: fetcher,
enabled: () => (query) => {...}
})
If you'd like to try it, you can install it with:
npm i https://pkg.pr.new/@tanstack/vue-query@9276
I'm personally not strongly opinionated about whether the enabled getter behavior should be retained in the next major version. The original intent behind supporting it was to offer a more flexible and ergonomic API that aligns with Vue’s ecosystem, particularly the MaybeRefOrGetter pattern.
As a small side note, I do hope that some of the current flexibility could be reduced in the next version to help make the package easier to maintain. Though that may be slightly off topic.
Thanks again for the thoughtful feedback. I truly hope this update is helpful to you.