news 2026/9/11 18:03:53

Svelte Query useIsFetching 详解:响应式统计正在请求中的查询数量

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Svelte Query useIsFetching 详解:响应式统计正在请求中的查询数量

Svelte Query useIsFetching 详解:响应式统计正在请求中的查询数量

【免费下载链接】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

useIsFetching是 Svelte Query(@tanstack/svelte-query)提供的一个响应式工具函数,用于统计当前正在向后端发起请求(fetching)的查询数量,并返回一个可直接在 Svelte 模板与逻辑块中使用的响应式值。它非常适合实现全局加载指示器、刷新进度提示等跨查询共享 UI 状态,在 Svelte Query 参考文档 中作为核心函数 API 收录。读完本文,你将掌握它的签名、参数过滤规则、返回值语义,以及它从QueryClientQueryCache的完整底层实现链路。

函数签名与核心能力

useIsFetching的完整类型签名如下:

function useIsFetching(filters?, queryClient?): ReactiveValue<number>;

它的定义位于 packages/svelte-query/src/useIsFetching.svelte.ts#L40,并通过 packages/svelte-query/src/index.ts#L28 从@tanstack/svelte-query包对外导出:

export { useIsFetching } from './useIsFetching.svelte.js'

它接收两个可选参数——filters(用于缩小统计范围的QueryFilters)与queryClient(自定义客户端实例),返回一个ReactiveValue<number>。与 React Query 的useIsFetching返回普通数字不同,Svelte 版本返回的是 Svelte 5 运行时的响应式容器对象,读取其中的.current属性即可拿到当前正在请求的查询数量,且读取行为会被 Svelte 的响应式系统自动追踪。

参数详解

filters?:QueryFilters

filtersQueryFilters<readonly unknown[]>类型,用于收窄"统计哪些查询"的范围。省略该参数时,统计所有正在请求的查询

QueryFilters定义于 packages/query-core/src/utils.ts#L27,其字段如下:

字段类型说明
type'all' \| 'active' \| 'inactive'只统计 active 查询、inactive 查询或全部查询
exactboolean是否精确匹配queryKey(默认前缀匹配)
predicate(query: Query) => boolean自定义谓词函数,逐个过滤查询
queryKeyTQueryKey \| TuplePrefixes<TQueryKey>按查询键匹配,支持前缀匹配
staleboolean只统计过期(stale)或未过期的查询
fetchStatusFetchStatus按请求状态过滤,FetchStatus取值为'fetching' \| 'paused' \| 'idle'(定义于 packages/query-core/src/types.ts#L665)

最常用的写法是传入queryKey进行前缀匹配。例如useIsFetching({ queryKey: ['posts'] })会统计所有以['posts']开头的查询键对应的请求;若需精确匹配,可加exact: true。也可以通过predicate做更细粒度的判断,例如只统计某个特定数据源的请求。

queryClient?:QueryClient

queryClient用于指定自定义的QueryClient实例。省略时,useIsFetching会通过 Svelte 的 context 机制获取最近的QueryClient。这一解析逻辑位于 packages/svelte-query/src/useQueryClient.ts:

export function useQueryClient(queryClient?: QueryClient): QueryClient { if (queryClient) return queryClient return getQueryClientContext() }

因此在大多数场景下,只要组件树外层通过QueryClientProvider(或setQueryClientContext)注入了客户端,直接调用useIsFetching()即可。只有需要绕过 context(例如测试环境、独立模块)时才显式传入第二个参数。

返回值 ReactiveValue<number> 的语义

返回的ReactiveValue<number>是 Svelte Query 对 Svelte 5 响应式运行时的封装。要读取当前统计值,必须访问.current

<script lang="ts"> import { useIsFetching } from '@tanstack/svelte-query' const isFetching = useIsFetching() </script> {#if isFetching.current} <div>Queries are fetching in the background...</div> {/if}

其实现位于 packages/svelte-query/src/containers.svelte.ts#L8-L21:

export class ReactiveValue<T> implements Box<T> { #fn #subscribe constructor(fn: () => T, onSubscribe: Subscriber) { this.#fn = fn this.#subscribe = createSubscriber((update) => onSubscribe(update)) } get current() { this.#subscribe() return this.#fn() } }

每次访问current都会触发两件事:

  1. 调用createSubscriber(来自svelte/reactivity)建立的订阅逻辑,把当前读取位置注册为queryCache的监听者;
  2. 执行内部的fn(),实时计算并返回当前的 fetching 数量。

queryCache后续发生变更(查询开始/结束请求)时,订阅回调会通知 Svelte 的响应式系统,让所有读取过current的模板表达式自动重新求值——这正是useIsFetching能"响应式"跟随请求状态变化的根本原因。

使用示例

场景一:按 queryKey 前缀过滤,展示局部刷新提示

原文档给出的典型用法是只关心某个数据域内的请求。以下代码统计所有以['posts']为前缀的查询是否正在请求,并据此显示刷新提示:

<script lang="ts"> import { useIsFetching } from '@tanstack/svelte-query' // How many queries matching the posts prefix are fetching? const isFetchingPosts = useIsFetching({ queryKey: ['posts'] }) </script> {#if isFetchingPosts.current} <span>Refreshing posts...</span> {/if}

场景二:全局加载指示器

不传任何参数时,useIsFetching统计的是 queryCache 中所有正在请求的查询,包括后台静默刷新、预取等不在当前屏幕上渲染的查询。这非常适合做应用级的全局进度指示:

<script lang="ts"> import { useIsFetching } from '@tanstack/svelte-query' const isFetching = useIsFetching() </script> {#if isFetching.current} <div>Queries are fetching in the background...</div> {/if}

注意它与单个查询结果里的isFetching语义不同:useQuery返回的isFetching只反映该查询自身是否在请求,而useIsFetching是跨查询的聚合视角。

场景三:组合过滤条件

实际项目中可以组合多个过滤字段,精确控制统计口径。例如只统计 active(有组件正在观察)且已过期(stale)的查询:

<script lang="ts"> import { useIsFetching } from '@tanstack/svelte-query' const isFetchingActiveStale = useIsFetching({ type: 'active', stale: true, }) </script> {#if isFetchingActiveStale.current} <p>Active stale queries are refetching…</p> {/if}

也可以配合enabled条件查询(参考 createQuery)观察请求的生命周期:请求发起时计数 +1,请求完成时归零。

底层实现原理

useIsFetching的完整实现非常精简,核心只有几行(packages/svelte-query/src/useIsFetching.svelte.ts#L40-L51):

export function useIsFetching( filters?: QueryFilters, queryClient?: QueryClient, ): ReactiveValue<number> { const client = useQueryClient(queryClient) const queryCache = client.getQueryCache() return new ReactiveValue( () => client.isFetching(filters), (update) => queryCache.subscribe(update), ) }

整个数据流可以拆解为三个环节:

1. 获取客户端与缓存。通过useQueryClient(queryClient)拿到实际使用的QueryClient,再通过client.getQueryCache()取得底层的QueryCacheQueryCache是查询实例的存储与订阅中心。

2. 计算 fetching 数量。每次响应式求值时调用client.isFetching(filters)。该方法定义于 packages/query-core/src/queryClient.ts#L109-L114:

isFetching<TQueryFilters extends QueryFilters<any> = QueryFilters>( filters?: TQueryFilters, ): number { return this.#queryCache.findAll({ ...filters, fetchStatus: 'fetching' }) .length }

可以看到,无论调用者是否传入过滤条件,isFetching都会强制附加fetchStatus: 'fetching',然后在 queryCache 中查找所有满足条件的查询并返回数量。

3. 订阅变更。构造ReactiveValue时传入(update) => queryCache.subscribe(update)。每当 queryCache 中任何查询的状态发生变化(例如请求开始、请求结束、缓存被写入),QueryCache都会触发订阅回调,从而驱动所有读取过isFetching.current的 Svelte 表达式重新执行。

一个值得注意的细节:fetching 与 paused 的区分

FetchStatus有三种取值:'fetching' | 'paused' | 'idle'(见 packages/query-core/src/types.ts#L665)。由于isFetching强制按fetchStatus: 'fetching'过滤,处于paused(例如网络离线而暂停请求)状态的查询不会被计入统计结果。这一点从源码逻辑可以直接推断:只有真正在发请求的查询才会被findAll选中。

测试验证:请求开始与结束时的计数变化

仓库中为useIsFetching提供了对应的测试组件与用例,位于 packages/svelte-query/tests/useIsFetching/useIsFetching.svelte.test.ts。测试组件 Base.svelte 中先通过setQueryClientContext(queryClient)注入客户端,再创建一个受ready开关控制的查询与一个useIsFetching()

<script lang="ts"> import { setQueryClientContext } from '../../src/context.js' import { createQuery, useIsFetching } from '../../src/index.js' setQueryClientContext(queryClient) let ready = $state(false) const query = createQuery(() => ({ queryKey: queryKey(), queryFn: () => sleep(10).then(() => 'test'), enabled: ready, })) const isFetching = useIsFetching() </script> <button onclick={() => (ready = true)}>setReady</button> <div>isFetching: {isFetching.current}</div>

测试用例验证了计数的动态变化(useIsFetching.svelte.test.ts#L19-L31):

  • 初始状态显示isFetching: 0
  • 点击按钮启用查询后(enabled: true触发请求),计数变为1
  • 查询完成(10ms 的sleep结束)后,计数回到0

这直接印证了"查询开始请求 → 计数 +1,请求结束 → 计数归零"的响应式行为,也说明useIsFetching会跨查询生命周期持续跟踪状态。

常见问题与注意事项

  • 读取时一定要用.currentuseIsFetching返回的是ReactiveValue容器而非原始数字,忘记访问.current会在模板中拿到对象本身,无法正确渲染。
  • 默认前缀匹配:传入queryKey时默认按前缀匹配,['posts']会匹配['posts', 1]['posts', 'detail']等;需要精确匹配时显式设置exact: true
  • 不区分屏幕内外:不带参数调用时,后台刷新、预取(prefetch)等不在当前组件观察范围内的请求也会被计入,这正是设计上用于全局加载指示的原因。
  • 自定义 QueryClient 场景:多客户端架构下,可通过第二个参数显式指定QueryClient,否则始终使用最近 context 中的实例。
  • paused 查询不计入:网络离线等导致暂停的请求不会让计数 +1,因为底层强制按fetchStatus: 'fetching'过滤。

小结

useIsFetching用极简的 API 抽象了"跨查询聚合请求状态"这一常见需求:参数层通过QueryFilters提供前缀匹配、精确匹配、谓词过滤等丰富的统计口径;返回值层借助ReactiveValuequeryCache.subscribe实现了完全响应式的更新链路;底层则由QueryClient.isFetching统一收敛到findAll({ fetchStatus: 'fetching' })。无论是页面级"正在刷新"提示、应用级全局加载条,还是多查询协同的业务场景,它都是 Svelte 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),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/11 18:03:13

用 Trino + Apache Polaris 把 RustFS 当湖仓存储底座:Iceberg 直查实战

目录 问题背景&#xff1a;湖仓查询为什么要把存储和引擎解耦RustFS 在湖仓里的位置&#xff1a;S3 兼容的数据文件底座一键拉起&#xff1a;rustfs polaris trino 的 docker-compose跑通直查&#xff1a;Iceberg catalog 配置与 SQL 验证边界与取舍&#xff1a;path-style …

作者头像 李华
网站建设 2026/9/11 18:02:58

DirectX 12资源上传与读回:CPU-GPU数据移动的底层原理与工程实践

1. 这不是“拷贝粘贴”&#xff0c;而是 CPU 与 GPU 之间的精密物流调度 DirectX 12 学习笔记&#xff1a;资源上传与读回&#xff0c;数据如何在 CPU 和 GPU 之间移动——这个标题里藏着一个被绝大多数初学者严重低估的真相&#xff1a; 在 D3D12 里&#xff0c;你写的每一行…

作者头像 李华
网站建设 2026/9/11 18:02:46

与技术人员以及技术人员对外的沟通指南

与技术人员以及技术人员对外的沟通指南 一、写在前面 技术人员往往性格直白、表达直接&#xff0c;习惯用技术可行性和自身能力边界来判断问题。这不是缺点&#xff0c;而是职业训练带来的思维习惯。 沟通卡在「看起来很简单&#xff0c;对方却觉得做不了」或「技术上对了&…

作者头像 李华
网站建设 2026/9/11 18:02:39

GrapesJS Property 属性模型完全指南:从配置定义到 CSS 目标同步

GrapesJS Property 属性模型完全指南&#xff1a;从配置定义到 CSS 目标同步 【免费下载链接】grapesjs Free and Open source Web Builder Framework. Next generation tool for building templates without coding 项目地址: https://gitcode.com/GitHub_Trending/gr/grape…

作者头像 李华
网站建设 2026/9/11 18:02:10

MuJoCo肌腱系统深度解析:包络路径与肌肉仿真实战

MuJoCo肌腱系统深度解析&#xff1a;包络路径与肌肉仿真实战 【免费下载链接】mujoco Multi-Joint dynamics with Contact. A general purpose physics simulator. 项目地址: https://gitcode.com/GitHub_Trending/mu/mujoco 构建生物力学或肌肉驱动的机器人模型时&…

作者头像 李华
网站建设 2026/9/11 18:01:42

Beads 评论管理实战:精通 `bd comments` 与 `bd comment` 命令

Beads 评论管理实战&#xff1a;精通 bd comments 与 bd comment 命令 【免费下载链接】beads Beads - A memory upgrade for your coding agent 项目地址: https://gitcode.com/GitHub_Trending/beads1/beads 导读 Beads 将 issue 的评论作为一等公民纳入版本化存储&a…

作者头像 李华