如何在方法内调用TanStack Vue Query的GET请求?
Vue Query在副作用函数中调用的问题与解决方案
问题描述
在按钮点击等副作用函数中调用useQuery时,抛出错误:vue-query hooks can only be used inside setup() function or functions that support injection context。示例代码如下:
api.js
export const getAPIRequest = (url, params={}) => useQuery({ queryKey: [url, params], queryFn: fetch(url, { method: 'GET', headers: { 'Content-Type': 'application/json' }, }) })
component.vue
<script setup> const getDetails = () => { const { data: data } = getAPIRequest('/some-url') return data } </script> <template> <button @click="getDetails">Click Here</button> </template>
疑问点:
- Vue Query是否只能在setup函数中使用?
- 如何规划项目来处理按钮点击或输入触发的副作用?
- 是否需要转为POST请求,或是有更好的方案?
- 如何保留Vue Query的缓存、后台更新、响应式结果等特性?
解决方案
1. Vue Query hooks的使用限制
是的,useQuery这类Vue Query hooks必须在setup函数内部,或是由setup调用的自定义hooks中使用。这是因为Vue Query依赖Vue的依赖注入系统来获取QueryClient实例,而事件处理函数(比如按钮点击回调)不在注入上下文范围内,直接调用会报错。
2. 处理用户交互触发的查询(保留Vue Query特性)
不需要转为POST请求(POST属于mutation,用于修改数据场景),针对单纯获取数据的交互触发场景,有两种推荐方案:
方案一:用enabled选项控制查询执行
在setup中声明useQuery,通过响应式变量控制enabled参数,点击按钮时更新变量来触发查询:
<script setup> import { ref } from 'vue' import { useQuery } from '@tanstack/vue-query' const shouldFetch = ref(false) const { data, refetch } = useQuery({ queryKey: ['some-url'], queryFn: () => fetch('/some-url', { method: 'GET', headers: { 'Content-Type': 'application/json' } }).then(res => res.json()), enabled: shouldFetch.value // 初始不执行查询 }) const getDetails = () => { // 方式1:更新enabled触发首次查询 shouldFetch.value = true // 方式2:调用refetch,支持重复触发查询 // refetch() } </script> <template> <button @click="getDetails">Click Here</button> <div v-if="data">{{ data }}</div> </template>
方案二:用QueryClient手动触发查询
通过useQueryClient获取客户端实例,在事件回调中调用fetchQuery或prefetchQuery,手动触发查询的同时依然能利用缓存机制:
<script setup> import { useQueryClient } from '@tanstack/vue-query' const queryClient = useQueryClient() const getDetails = async () => { // fetchQuery返回数据,同时自动缓存结果 const data = await queryClient.fetchQuery({ queryKey: ['some-url'], queryFn: () => fetch('/some-url', { method: 'GET', headers: { 'Content-Type': 'application/json' } }).then(res => res.json()), // 可配置缓存策略,比如设置数据过期时间 staleTime: 5 * 60 * 1000 }) // 处理获取到的数据 console.log(data) } </script> <template> <button @click="getDetails">Click Here</button> </template>
3. 项目规划建议
- 封装数据获取逻辑为自定义hooks:把
useQuery的调用放在自定义hooks中,在组件的setup里引入使用,保证hooks始终在注入上下文内执行。 - 区分查询与mutation:GET请求用
useQuery(或手动fetchQuery)处理获取数据场景,POST/PUT/DELETE等修改数据的请求用useMutation。 - 利用Vue Query的缓存特性:不管是
enabled控制还是手动fetchQuery,都能享受缓存、后台自动刷新、数据过期等特性,只需合理配置queryKey和缓存参数即可。
内容的提问来源于stack exchange,提问作者Niku Nitin
相关产品推荐
相关产品推荐

