禁用/暂停查询
如果你希望禁用某个查询,使其不自动执行,可以使用 enabled = false 选项。enabled 选项还支持传入一个返回布尔值的回调函数。
当 enabled 为 false 时:
- 如果查询已缓存数据,则查询将初始化为
status === 'success'或isSuccess状态。 - 如果查询没有缓存数据,则查询将从
status === 'pending'和fetchStatus === 'idle'状态开始。 - 查询在挂载时不会自动拉取。
- 查询不会在后台自动重新拉取。
- 查询会忽略查询客户端的
invalidateQueries和refetchQueries调用(这些调用通常会触发查询重新拉取)。 - 通过
useQuery返回的refetch可用于手动触发查询拉取。但该方法不适用于skipToken。
使用 TypeScript 的用户可能更倾向于使用 skipToken 作为
enabled = false的替代方案。
1<script setup>2import { useQuery } from '@tanstack/vue-query'34const { isLoading, isError, data, error, refetch, isFetching } = useQuery({5 queryKey: ['todos'],6 queryFn: fetchTodoList,7 enabled: false,8})9</script>10 11<template>12 <button @click="refetch()">Fetch Todos</button>13 <span v-if="isLoading">Loading...</span>14 <span v-else-if="isError">Error: {{ error?.message }}</span>15 <div v-else-if="data">16 <span v-if="isFetching">Fetching...</span>17 <ul>18 <li v-for="todo in data" :key="todo.id">{{ todo.title }}</li>19 </ul>20 </div>21 <span v-else>Not ready...</span>22</template>永久禁用查询会使你无法使用 TanStack Query 提供的许多优秀功能(例如后台重新拉取),而且这也不是符合惯用法的做法。它会迫使你从声明式方式(定义查询应在何时运行)转向命令式方式(点击此处时才拉取)。此外,你无法向 refetch 传递参数。很多时候,你真正需要的只是一个延迟查询(lazy query),即推迟初始拉取操作:
延迟查询(Lazy Queries)
enabled 选项不仅可以用于永久禁用查询,还可以在后续某个时间点启用或禁用查询。一个典型示例是筛选表单:你仅希望在用户输入筛选值后才发起首次请求:
1<script setup>2import { useQuery } from '@tanstack/vue-query'34const filter = ref('')5const isEnabled = computed(() => !!filter.value)6const { data } = useQuery({7 queryKey: ['todos', filter],8 queryFn: () => fetchTodos(filter),9 // ⬇️ disabled as long as the filter is empty10 enabled: isEnabled,11})12</script>13 14<template>15 <span v-if="data">Filter was set and data is here!</span>16</template>isLoading(此前名为 isInitialLoading)
延迟查询从一开始就会处于 status: 'pending' 状态,因为 pending 表示尚无数据。从技术上讲这是正确的;但由于此时并未实际拉取任何数据(查询尚未 启用),因此你很可能无法使用该标志来显示加载指示器。
如果你正在使用已禁用或延迟的查询,可改用 isLoading 标志。这是一个派生标志,其计算逻辑为:
isPending && isFetching
因此,仅当查询当前正在进行首次拉取时,该标志才为 true。
使用 skipToken 类型安全地禁用查询
如果你正在使用 TypeScript,可以使用 skipToken 来禁用查询。当你需要根据某个条件禁用查询,同时又希望保持类型安全性时,此方法非常有用。
重要提示:
useQuery返回的refetch不适用于skipToken。对使用skipToken的查询调用refetch()将导致Missing queryFn错误,因为此时不存在有效的查询函数可供执行。如需手动触发查询,请考虑改用enabled: false,它能确保refetch()正常工作。除这一限制外,skipToken的行为与enabled: false完全一致。
1<script setup>2import { useQuery, skipToken } from '@tanstack/vue-query'34const filter = ref('')5const queryFn = computed(() =>6 !!filter.value ? () => fetchTodos(filter) : skipToken,7)8const { data } = useQuery({9 queryKey: ['todos', filter],10 // ⬇️ disabled as long as the filter is undefined or empty11 queryFn: queryFn,12})13</script>14 15<template>16 <span v-if="data">Filter was set and data is here!</span>17</template>