拓冰建站拓冰建站
首页 / 资讯中心 / 正文

Svelte Query 的 CreateInfiniteQueryOptions 类型全解:泛型参数、无限滚动配置与源码级原理

Svelte Query 的 CreateInfiniteQueryOptions 类型全解泛型参数、无限滚动配置与源码级原理【免费下载链接】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本文围绕 TanStack QuerySvelte Query中createInfiniteQuery的配置选项类型CreateInfiniteQueryOptions展开完整讲解其 5 个泛型参数的含义、底层继承结构InfiniteQueryObserverOptions→QueryObserverOptionsInfiniteQueryPageParamsOptions以及分页相关的核心选项并结合packages/svelte-query与packages/query-core的真实实现给出可在 Svelte 5 组件中直接运行的加载更多与滚动加载完整示例。读完你将对无限查询的类型系统与分页机制有源码级的理解。一、类型别名是什么一句话定位CreateInfiniteQueryOptions是 Svelte Query 为createInfiniteQuery定义的类型别名它不是一个独立的选项集合而是对 query-core 中InfiniteQueryObserverOptions的类型转发。其完整定义位于 packages/svelte-query/src/types.ts:53/** Options for createInfiniteQuery */ export type CreateInfiniteQueryOptions TQueryFnData unknown, TError DefaultError, TData TQueryFnData, TQueryKey extends QueryKey QueryKey, TPageParam unknown, InfiniteQueryObserverOptions TQueryFnData, TError, TData, TQueryKey, TPageParam 同时在 packages/svelte-query/src/types.ts:68 定义了与之配对的返回值类型CreateInfiniteQueryResult其本质是InfiniteQueryObserverResult两者一起构成createInfiniteQuery的入参 / 出参类型契约。值得注意该类型处于 Svelte 适配层真正的选项字段queryKey、queryFn、initialPageParam、getNextPageParam等都定义在 query-core 中Svelte 层只负责复用。这保证了 Svelte、React、Vue、Solid 等所有框架的无限查询选项行为完全一致。二、五个泛型参数逐一拆解CreateInfiniteQueryOptions接受 5 个类型参数全部带有默认值。在实际使用中绝大多数开发者只需显式指定前 12 个其余由 TypeScript 自动推断。泛型参数约束默认值作用TQueryFnData—unknown查询函数queryFn单页返回的原始数据类型如一个项目数组或带游标的分页对象TError—DefaultError查询失败时的错误类型默认是 query-core 导出的DefaultError通常为ErrorTData—TQueryFnData经过select转换后暴露给组件的数据类型未使用select时与TQueryFnData相同TQueryKeyextends QueryKeyQueryKey查询键类型用于缓存标识与queryFn上下文类型推导TPageParam—unknown页码/游标参数类型如number、string或自定义 cursor 对象从源码注释看TData的默认值是TQueryFnData而非InfiniteDataTQueryFnData这是因为无限查询的数据在运行时是分页数组结构InfiniteData但类型层面允许通过select把它投影为任意形态createInfiniteQuery函数本身createInfiniteQuery.ts在泛型默认值上使用了TData InfiniteDataTQueryFnData二者并不矛盾——后者是未使用 select 时的天然形态前者是选项层面允许你改写 TData 的自由度。三、底层继承结构无限查询选项从哪来InfiniteQueryObserverOptions定义在 packages/query-core/src/types.ts:457它同时继承了两个接口export interface InfiniteQueryObserverOptions... extends QueryObserverOptions TQueryFnData, TError, TData, InfiniteDataTQueryFnData, TPageParam, TQueryKey, TPageParam , InfiniteQueryPageParamsOptionsTQueryFnData, TPageParam {}这意味着你传给createInfiniteQuery的选项对象由两部分组成普通查询选项QueryObserverOptionsenabled、staleTime、gcTime、retry、refetchInterval、refetchOnWindowFocus、refetchOnReconnect、refetchOnMount、retryOnMount、throwOnError、select、suspense、placeholderData、notifyOnChangeProps、structuralSharing、queryKeyHashFn、initialDataUpdatedAt、meta等与createQuery完全一致分页专属选项InfiniteQueryPageParamsOptionsinitialPageParam、getNextPageParam、getPreviousPageParam。分页选项接口定义于 packages/query-core/src/types.ts:287export interface InfiniteQueryPageParamsOptions TQueryFnData unknown, TPageParam unknown, extends InitialPageParamTPageParam { getPreviousPageParam?: GetPreviousPageParamFunctionTPageParam, TQueryFnData getNextPageParam?: GetNextPageParamFunctionTPageParam, TQueryFnData }其中initialPageParam通过InitialPageParamTPageParam接口成为必填项这正是它区别于普通查询的关键之一。getNextPageParam/getPreviousPageParam都是可选函数其签名分别对应GetNextPageParamFunction与GetPreviousPageParamFunctiontypes.ts:196-208export type GetNextPageParamFunctionTPageParam, TQueryFnData unknown ( lastPage: TQueryFnData, // 当前最后一页数据 allPages: ArrayTQueryFnData, // 已加载的全部页面 lastPageParam: TPageParam, // 当前最后一页的页码参数 allPageParams: ArrayTPageParam, // 已使用的全部页码参数 ) TPageParam | undefined | null返回undefined或null即表示没有下一页/上一页。3.1 无限数据的存储形态InfiniteData无限查询的缓存数据不是普通数据而是InfiniteData结构types.ts:210-213export interface InfiniteDataTData, TPageParam unknown { pages: ArrayTData // 按顺序排列的每一页数据 pageParams: ArrayTPageParam // 与 pages 一一对应的页码参数 }模板中遍历query.data.pages即可逐页渲染pageParams则记录了每页对应的游标供参数回放与数据一致性判断使用。四、分页核心选项的语义与默认值结合源码注释types.ts:231-301 与 types.ts:315-440以下是无限查询中最关键的几个选项queryKey必填查询的唯一标识所有选项的缓存基准queryFn的QueryFunctionContext会携带该 key。queryFn: (context) PromiseTQueryFnData单页获取函数。上下文对象中会注入pageParam类型为TPageParam例如({ pageParam }) fetchProjects(pageParam)。initialPageParam必填第一页的页码参数类型为TPageParam。query-core 的InitialPageParam接口强制要求此字段漏写会直接编译报错。getNextPageParam根据最后一页推断下一页游标返回值决定hasNextPage与fetchNextPage的行为。getPreviousPageParam根据第一页推断上一页游标返回值决定hasPreviousPage与fetchPreviousPage。maxPages缓存中最多保留的页数超出后最旧页面会被丢弃types.ts:278-280 注释Maximum number of pages to store in the data of an infinite query适合防止无限滚动内存无限增长。select将InfiniteData投影为TData的类型转换函数一旦使用TData就不再等于InfiniteData形态。enabled默认true设为false或返回false的函数可禁用自动请求无限查询也可借此实现依赖查询。staleTime默认0数据视为过期的毫秒数设为Infinity则永不视为过期。refetchInterval默认false轮询刷新频率设为数字则持续定时刷新。refetchOnWindowFocus/refetchOnReconnect/refetchOnMount默认true窗口聚焦、网络重连、挂载时是否在数据过期时重新拉取。retry/retryDelay/networkMode/gcTime重试次数与退避、网络模式online | always | offlineFirst、非活动缓存驻留时间默认5 * 60 * 1000毫秒由 QueryClient 默认值决定。4.1 hasNextPage / hasPreviousPage 的判定原理hasNextPage并不是一个存储状态而是由 packages/query-core/src/infiniteQueryBehavior.ts:159-175 实时计算的export function hasNextPage(options, data) { return getNextPageParam(options, data) ! null } export function hasPreviousPage(options, data) { if (!data || !options.getPreviousPageParam) return false return getPreviousPageParam(options, data) ! null }即调用getNextPageParam/getPreviousPageParam后返回值非空就认为还有更多页。因此这两个函数的返回值约定TPageParam | undefined | null直接决定了Load More按钮的可用状态。五、实战在 Svelte 5 组件中使用 CreateInfiniteQueryOptionscreateInfiniteQuery的签名createInfiniteQuery.ts:152-169要求选项以Accessor即() Options形式传入以便选项可以响应式更新第二个可选参数queryClient也是AccessorQueryClient缺省时使用最近上下文中的客户端。其内部实现最终委托给createBaseQuery并将 observer 指定为InfiniteQueryObservercreateInfiniteQuery.ts:171-179。5.1 完整示例一Load More 按钮分页以下代码完整取自 createInfiniteQuery.ts:69-106 的官方示例可直接运行于 Svelte 5script langts import { createInfiniteQuery } from tanstack/svelte-query const query createInfiniteQuery(() ({ queryKey: [projects], queryFn: ({ pageParam }) fetchProjects(pageParam), initialPageParam: 0, getNextPageParam: (lastPage) lastPage.nextId, })) /script {#if query.isPending} Loading... {:else if query.isError} spanError: {query.error.message}/span {:else} ul {#each query.data.pages as page} {#each page.projects as project (project.id)} li{project.name}/li {/each} {/each} /ul button onclick{() query.fetchNextPage()} disabled{!query.hasNextPage || query.isFetching} {query.isFetchingNextPage ? Loading more... : query.hasNextPage ? Load More : Nothing more to load} /button {/if}这里query的类型即CreateInfiniteQueryResult内部为InfiniteQueryObserverResult组件可访问的分页字段有data.pages、data.pageParams、fetchNextPage()、fetchPreviousPage()、hasNextPage、hasPreviousPage、isFetchingNextPage、isFetchingPreviousPage、isFetching、isPending、isError、error等。5.2 完整示例二IntersectionObserver 滚动加载无限滚动场景下用IntersectionObserver监听列表末尾哨兵元素进入视口即触发fetchNextPage()createInfiniteQuery.ts:108-150script langts import { createInfiniteQuery } from tanstack/svelte-query const query createInfiniteQuery(() ({ queryKey: [projects], queryFn: ({ pageParam }) fetchProjects(pageParam), initialPageParam: 0, getNextPageParam: (lastPage) lastPage.nextId, })) let sentinel: HTMLDivElement | undefined $state() $effect(() { if (sentinel null || !query.hasNextPage || query.isFetching) return const observer new IntersectionObserver(([entry]) { if (entry?.isIntersecting) query.fetchNextPage() }) observer.observe(sentinel) return () observer.disconnect() }) /script {#if query.isPending} Loading... {:else if query.isError} spanError: {query.error.message}/span {:else} ul {#each query.data.pages as page} {#each page.projects as project (project.id)} li{project.name}/li {/each} {/each} /ul div bind:this{sentinel}/div {/if}关键点$effect中同时检查hasNextPage与isFetching避免在加载中重复触发bind:this{sentinel}绑定哨兵元素effect 返回observer.disconnect()完成清理。六、选项复用infiniteQueryOptions 与命令式 API同一份CreateInfiniteQueryOptions不仅可传给createInfiniteQuery还可通过infiniteQueryOptions()工厂在声明式调用与命令式 API如queryClient.infiniteQuery/queryClient.fetchInfiniteQuery之间共享。该工厂定义于 packages/svelte-query/src/infiniteQueryOptions.ts:92-180其返回类型额外带上QueryKeyWithDataTag让queryKey携带推断出的数据类型。它有两个重载按是否提供initialData自动选择DefinedInitialDataInfiniteOptionsinfiniteQueryOptions.ts:32-48initialData必填且不能为undefined类型被NonUndefinedGuard收窄返回的查询结果在类型上被推导为DefinedCreateInfiniteQueryResultdata不会为undefined。UndefinedInitialDataInfiniteOptionsinfiniteQueryOptions.ts:11-30initialData仅允许undefined或通过守卫的函数形式代表没有初始数据。官方示例展示了带initialData的用法infiniteQueryOptions.ts:62-90——用空列表跳过首屏 loading即使后续刷新失败旧列表仍与错误提示共存script langts import { infiniteQueryOptions, createInfiniteQuery } from tanstack/svelte-query const projectsOptions infiniteQueryOptions({ queryKey: [projects], queryFn: ({ pageParam }) fetchProjects(pageParam), initialPageParam: 0, getNextPageParam: (lastPage) lastPage.nextId, initialData: { pages: [], pageParams: [] }, }) const query createInfiniteQuery(() projectsOptions) /script {#if query.isError} spanError: {query.error.message}/span {/if} ul {#each query.data.pages as page} {#each page.projects as project (project.id)} li{project.name}/li {/each} {/each} /ul七、类型参数的使用技巧与边界只需关注前两个参数实践中通常只显式标注TQueryFnData与TError或完全不标注TQueryKey、TPageParam、TData均可由queryKey/queryFn/select推导。TData用于select投影当select把InfiniteData转换为其他形状时TData应写成转换后的类型此时模板访问query.data得到的是投影结果。TPageParam决定分页方式基于页码的分页用number基于游标的分页用string复杂分页可传对象类型。getNextPageParam的返回值必须与initialPageParam、queryFn中的pageParam类型一致。TQueryKey extends QueryKey约束QueryKey是 query-core 定义的只读数组类型元素为string | number | boolean | null | undefined | object | readonly unknown[]的递归联合自定义 key 结构必须可赋给该约束。八、测试与验证类型与行为的双重保证仓库在 packages/svelte-query/tests/createInfiniteQuery/createInfiniteQuery.test-d.ts 中对该 API 做了类型级测试编译期断言CreateInfiniteQueryOptions各泛型组合的可赋值性并在 createInfiniteQuery.svelte.test.ts 及Base.svelte、InitialData.svelte、Select.svelte等组件测试中验证了分页行为。query-core 侧还有针对InfiniteQueryObserver的行为测试packages/query-core/src/tests/infiniteQueryObserver.test.tsx覆盖fetchNextPage/fetchPreviousPage与DefaultedInfiniteQueryObserverOptions的默认值合并逻辑。这些测试共同确认只要选项对象满足CreateInfiniteQueryOptionsSvelte 适配层与 query-core 的 observer 即可无缝协作。九、总结CreateInfiniteQueryOptions是createInfiniteQuery的选项类型别名本质是InfiniteQueryObserverOptions的转发定义于 packages/svelte-query/src/types.ts:53。它包含 5 个泛型参数TQueryFnData、TError、TData、TQueryKey、TPageParam均带默认值绝大多数场景由类型推断完成。选项由普通查询选项 分页选项两部分构成其中initialPageParam必填getNextPageParam/getPreviousPageParam的返回值直接决定hasNextPage/hasPreviousPage。数据以InfiniteData { pages, pageParams }形态缓存配合fetchNextPage/fetchPreviousPage、isFetchingNextPage等返回值字段可轻松实现Load More 按钮与滚动无限加载两类典型交互。【免费下载链接】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),仅供参考
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门