)
Preact Query 指南禁用与暂停查询Disabling / Pausing Queries【免费下载链接】query Powerful asynchronous state management, server-state utilities and data fetching for the web. TS/JS, React Query, Solid Query, Svelte Query and Vue Query.项目地址: https://gitcode.com/GitHub_Trending/qu/query在基于 Preact 的前端应用中tanstack/preact-query的useQuery并不总是希望组件挂载后立刻发起请求——例如用户点击后再加载、过滤条件尚未填写时不请求、或依赖项还不存在时等待。本指南围绕enabled选项与skipToken两大机制系统讲解如何禁用、延迟、按条件启动查询并厘清isPending、isFetching、isLoading在禁用场景下的区别。读完本文你将能正确实现惰性查询 / 依赖查询并在保持 TypeScript 类型安全的前提下禁用查询。本文对应仓库文档为 Preact Query 禁用查询指南该文档与 React Query 同主题指南 内容一一对应前者由后者以react-query → preact-query、React → Preact全局替换生成文中引用的实现代码均来自当前仓库。一、用enabled选项禁用自动执行想要让查询不自动运行最直接的入口是useQuery选项中的enabled。将其置为false查询便进入禁用状态queryObserver.ts 中对enabled做了校验它既可以是一个布尔值也可以是一个返回布尔值的回调函数——当回调形式出现时会在每次结果计算前通过resolveQueryValue取值这意味着你可以在渲染期间基于最新 props / state 动态决定是否启用查询。import { useQuery } from tanstack/preact-query function Todos() { const { isLoading, isError, data, error, refetch, isFetching } useQuery({ queryKey: [todos], queryFn: fetchTodoList, enabled: false, }) return ( div button onClick{() refetch()}Fetch Todos/button {data ? ( ul {data.map((todo) ( li key{todo.id}{todo.title}/li ))} /ul ) : isError ? ( spanError: {error.message}/span ) : isLoading ? ( spanLoading.../span ) : ( spanNot ready .../span )} div{isFetching ? Fetching... : null}/div /div ) }enabled false时查询的五种行为当enabled为false时查询呈现以下特征已有缓存数据若该queryKey此前已经取得过数据查询会被初始化为status success即isSuccess状态界面可立即渲染缓存内容没有缓存数据查询从status pending、fetchStatus idle开始——即还没有数据但也并没有在请求挂载时不自动请求不会在组件挂载时触发fetch不参与后台自动刷新不会响应窗口聚焦window focus、网络重连等触发条件进行后台 refetch忽略失效 / 刷新指令queryClient.invalidateQueries与queryClient.refetchQueries对它的常规调用会被忽略。在底层实现中这一系列约束正是由enabled贯穿query-core的多处判断完成的query.ts 中查询的isActive()只统计enabled ! false的观察者isStale()等失效判断同样把enabled false的查询排除在外queryObserver.ts 中shouldFetchOnMount、shouldFetchOn、shouldFetchOptionally均以resolveQueryValue(options.enabled, query) ! false作为前置门槛从源头杜绝了挂载自动请求与后台按需刷新的触发。与此同时useQuery返回的refetch依旧可用上述示例中点击按钮调用refetch()会手动触发一次请求。这是禁用态下唯一常规的拉取方式。二、永久禁用并非最佳实践声明式优于命令式文档特别提醒永久禁用enabled: false永远不变会让查询退出 TanStack Query 带来的大量特性例如后台刷新、自动失效同时也偏离了该库惯用的声明式用法——你实际上是在依赖声明与命令式手动拉取之间切换到了后者而且refetch无法携带参数你无法通过refetch(someArgs)把运行时入参传给queryFn。大多数情况下你真正需要的其实是一个惰性查询lazy query查询先不请求等到某个前置条件满足后再自然地启动——也就是把enabled从false变为true。三、惰性查询条件满足时自动启动enabled的价值不在于永久关死而在于在稍后某个时机由 false 翻转为 true。最经典的例子是过滤器表单只有用户输入了过滤值才发起第一次请求。下方代码展示的是仓库 Preact 禁用查询指南 中的示例。filter为空字符串时enabled: !!filter为false查询处于禁用态一旦用户提交过滤条件setFilter更新状态enabled变为true查询自动执行function Todos() { const [filter, setFilter] useState() const { data } useQuery({ queryKey: [todos, filter], queryFn: () fetchTodos(filter), // ⬇️ disabled as long as the filter is empty enabled: !!filter, }) return ( div // applying the filter will enable and execute the query FiltersForm onApply{setFilter} / {data TodosTable data{data} /} /div ) }注意queryKey与queryFn都依赖filter——把filter放进queryKey后每次过滤条件变化都会形成新的缓存条目这是依赖查询的标准写法。更多场景可延伸阅读 依赖查询Dependent Queries 与 查询基础Queries。isLoading与isPending/isFetching的区别惰性查询启动时status pending自始至终成立——因为pending的语义是还没有数据这在禁用期间也是成立的。但它并不能用来驱动 loading 动画禁用态下数据确实不存在isPending为 true可此时根本没有在请求。正确的选择是使用派生标记isLoading旧版称isInitialLoading。在 queryObserver.ts 中可以看到它的确切定义const isFetching newState.fetchStatus fetching const isPending status pending const isLoading isPending isFetching // 只在“首次请求进行中”为 true即isLoading isPending isFetching只有当查询正在第一次拉取数据时才为true。因此禁用期enabled: false、无数据→isPending: true、isFetching: false、isLoading: false适合展示Not ready...之类的占位首次请求进行中 →isPending: true、isFetching: true、isLoading: true可展示 spinner请求完成 → 进入success不再适用 loading 标记。在第一节的完整示例中正是通过isLoading区分Loading...与Not ready ...两种 UI 状态。四、TypeScript 类型安全禁用skipToken如果你在使用 TypeScript并且希望基于某个条件禁用查询同时保持完整的类型推导那么enabled false有一个更优的替代方案——skipTokenimport { skipToken, useQuery } from tanstack/preact-query function Todos() { const [filter, setFilter] useStatestring | undefined() const { data } useQuery({ queryKey: [todos, filter], // ⬇️ disabled as long as the filter is undefined or empty queryFn: filter ? () fetchTodos(filter) : skipToken, }) return ( div // applying the filter will enable and execute the query FiltersForm onApply{setFilter} / {data TodosTable data{data} /} /div ) }filter为undefined时queryFn传入skipToken查询被禁用一旦filter有值queryFn立即替换为真正的取数函数。相比enabled它的优势是类型层面的安全性在filter可能为undefined的场景下你无需编写fetchTodos(filter!)这种非空断言——类型系统会保证queryFn只在filter存在时才可能被真正调用。实现层面skipToken是什么skipToken定义于 query-core/src/utils.ts本质上是一个Symbol()并导出了对应的类型别名SkipToken在QueryClient的默认值归一化阶段queryClient.ts 会做显式转换if (defaultedOptions.queryFn skipToken) { defaultedOptions.enabled false }也就是说skipToken在运行时会被自动映射为enabled: false两者行为等价唯一的差别见下文refetch 限制。正因如此tanstack/preact-query完整重导出了query-core见 packages/preact-query/src/index.ts你才能直接import { skipToken } from tanstack/preact-query无需单独引入 query-core。refetch与skipToken的限制重要重要当queryFn为skipToken时useQuery返回的refetch()不会生效。此时调用refetch()会抛出Missing queryFn错误——因为没有可执行的查询函数。若你需要手动触发查询请改用enabled: false它对refetch()是放行的。除此之外skipToken与enabled: false表现完全一致。原因同样在源码中当queryFn被解析时utils.ts 中的 ensureQueryFn 会对queryFn skipToken或缺失的情况返回一个必定 reject的函数错误信息即Missing queryFn: queryHash。因此手动refetch拿到的是一个必然失败的查询函数。开发环境下若误调utils.ts 还会额外在控制台打印一条配置错误提示。skipToken的适用边界需要留意skipToken并非任何查询 API 都能使用useQuery/useQueries/useInfiniteQuery支持可通过queryOptions()/infiniteQueryOptions()与它们搭配见 queryOptions.ts 中skipToken重载的 JSDoc 示例Suspense 系列useSuspenseQuery、useSuspenseInfiniteQuery、useSuspenseQueries不允许传入skipToken。Suspense 模式的 Hook 无法渲染禁用态因此 useSuspenseQuery.ts 等实现会在开发环境打印skipToken is not allowed for useSuspenseQuery之类的错误类型层面也通过重载将其排除参见 types.ts 相关注释Prefetch 系列usePrefetchQuery、usePrefetchInfiniteQuery同样不允许因为预取必然需要一个真正执行的查询函数见 types.ts。五、禁用状态建模小结目标推荐方式refetch()手动触发类型安全永久禁用 手动按钮触发enabled: false✅ 可用需要自己处理可空入参条件满足后自动启动惰性查询enabled: !!condition或回调—需要自己处理可空入参条件满足后自动启动 全程类型安全queryFn: cond ? fn : skipToken❌ 不可用Missing queryFn✅ 编译器保证Suspense / Prefetch 下的禁用用enabled: false不要用skipToken—遵循对应 Hook 的类型约束辅助判断 UI 状态时请记住isLoading isPending isFetching只有它才能表达正在第一次加载禁用但无数据时用isPending单独判断展示 Not ready 类占位即可。六、结语禁用与暂停查询是 TanStack Query 数据流控制的重要一环。enabled负责声明式地描述查询的运行依赖适合实现过滤器、搜索框等典型的惰性查询skipToken则在 TypeScript 场景下把同一思路做到了类型闭环。理解isPending/isFetching/isLoading的区分以及refetch在skipToken下的限制是避免按钮点了没反应loading 永远转圈等经典踩坑的关键。建议结合实际源码与 React Query 对应版本 对照阅读两个框架的指南内容与行为完全一致。【免费下载链接】query Powerful asynchronous state management, server-state utilities and data fetching for the web. TS/JS, React Query, Solid Query, Svelte Query and Vue Query.项目地址: https://gitcode.com/GitHub_Trending/qu/query创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考