译零 TransZero · TanStack Query 中文文档
主站

禁用/暂停查询

更新于 2026-11-02 Preact 查看英文原文 ↗

如果你希望禁用某个查询,使其不自动执行,可以使用 enabled = false 选项。enabled 选项还支持传入一个返回布尔值的回调函数。

当 enabled 为 false 时:

  • 如果查询已有缓存数据,则该查询将初始化为 status === 'success' 或 isSuccess 状态。
  • 如果查询没有缓存数据,则该查询将从 status === 'pending' 和 fetchStatus === 'idle' 状态开始。
  • 查询在挂载时不会自动拉取。
  • 查询不会在后台自动重新拉取。
  • 查询会忽略查询客户端(QueryClient)的 invalidateQueries 和 refetchQueries 调用——这些调用通常会导致查询重新拉取。
  • 可通过 refetch(由 useQuery 返回)手动触发查询拉取。但该方法不适用于 skipToken。

使用 TypeScript 的用户可能更倾向于使用 skipToken 作为 enabled = false 的替代方案。

TypeScript
1function Todos() {2  const { isLoading, isError, data, error, refetch, isFetching } = useQuery({3    queryKey: ['todos'],4    queryFn: fetchTodoList,5    enabled: false,6  })7 8  return (9    <div>10      <button onClick={() => refetch()}>Fetch Todos</button>1112      {data ? (13        <ul>14          {data.map((todo) => (15            <li key={todo.id}>{todo.title}</li>16          ))}17        </ul>18      ) : isError ? (19        <span>Error: {error.message}</span>20      ) : isLoading ? (21        <span>Loading...</span>22      ) : (23        <span>Not ready ...</span>24      )}2526      <div>{isFetching ? 'Fetching...' : null}</div>27    </div>28  )29}

永久禁用查询会使你无法使用 TanStack Query 提供的许多优秀功能(例如后台重新拉取),而且这也不是符合惯用法的做法。它将你从声明式方式(定义查询应在何时运行的依赖关系)推向了命令式模式(我点击此处时才拉取)。此外,你无法向 refetch 传递参数。很多时候,你真正需要的只是一个延迟查询(lazy query),即推迟初始拉取操作:

延迟查询(Lazy Queries)

enabled 选项不仅可以用于永久禁用查询,还可以在稍后时间动态启用或禁用查询。一个典型示例是筛选表单:你仅希望在用户输入筛选值后才发起首次请求:

TypeScript
1function Todos() {2  const [filter, setFilter] = useState('')3 4  const { data } = useQuery({5    queryKey: ['todos', filter],6    queryFn: () => fetchTodos(filter),7    // ⬇️ disabled as long as the filter is empty8    enabled: !!filter,9  })10 11  return (12    <div>13      // 🚀 applying the filter will enable and execute the query14      <FiltersForm onApply={setFilter} />15      {data && <TodosTable data={data} />}16    </div>17  )18}

isLoading(此前名为 isInitialLoading)

延迟查询从一开始就会处于 status: 'pending' 状态,因为 pending 意味着尚无数据。从技术上讲这是正确的;但由于此时并未实际拉取任何数据(查询尚未 启用),因此你很可能无法使用此标志来显示加载指示器(loading spinner)。

如果你正在使用已禁用或延迟的查询,可改用 isLoading 标志。这是一个派生标志,其值根据以下条件计算得出:

isPending && isFetching

因此,仅当查询当前正首次拉取数据时,该标志才为 true。

使用 skipToken 类型安全地禁用查询

如果你正在使用 TypeScript,可通过 skipToken 来禁用查询。当你需要基于某个条件禁用查询,同时又希望保持类型安全性时,这种方式非常有用。

重要提示:refetch(由 useQuery 返回)无法与 skipToken 配合使用。对使用 skipToken 的查询调用 refetch() 将导致 Missing queryFn 错误,因为此时不存在有效的查询函数可供执行。如需手动触发查询,请考虑改用 enabled: false,它能确保 refetch() 正常工作。除这一限制外,skipToken 的行为与 enabled: false 完全一致。

TypeScript
1import { skipToken, useQuery } from '@tanstack/ppreact-query'2 3function Todos() {4  const [filter, setFilter] = useState<string | undefined>()5 6  const { data } = useQuery({7    queryKey: ['todos', filter],8    // ⬇️ disabled as long as the filter is undefined or empty9    queryFn: filter ? () => fetchTodos(filter) : skipToken,10  })11 12  return (13    <div>14      // 🚀 applying the filter will enable and execute the query15      <FiltersForm onApply={setFilter} />16      {data && <TodosTable data={data} />}17    </div>18  )19}

本页为 TanStack Query 文档(Preact 版)的非官方中文翻译,原文由上游团队维护,遵循 MIT 许可。 译文如有偏差,以英文原文为准。

译自上游 59d11de