
TanStack Preact Query 实战指南在 Preact 中构建强大的异步数据获取与缓存层【免费下载链接】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/preact-query是 TanStack Query 为 Preact 生态提供的官方数据层方案它把获取、缓存与更新异步数据这套能力以 Hooks 的形式带入 Preact 应用。本指南以本仓库 packages/preact-query/README.md 声明的 Quick Features 为骨架结合包内源码如 useBaseQuery.ts、useMutation.ts、suspense.ts与 examples/preact/simple 可运行示例逐项讲解如何接入 Provider 与 QueryClient、如何使用查询/变更/无限查询三类核心 Hooks以及自动缓存、stale-while-revalidate、并行与依赖查询、无限滚动、请求取消、Suspense 预取等特性背后的实现原理。读完本文你将能直接在 Preact 项目中搭建一套完整的服务端状态管理方案。一、认识 tanstack/preact-query1.1 它是什么在 Preact 应用中服务端状态server state与本地状态client state有着本质区别服务端数据是异步到达的、可能随时过期、由远程拥有并可能被他人修改。tanstack/preact-query提供了一系列 Hooks用于在 Preact 中获取、缓存和更新异步数据把上述复杂性收敛到声明式的 Hook 调用中。包的描述与定位可以在 package.json 中确认Hooks for managing, caching and syncing asynchronous and remote data in preact当前仓库版本为 5.102.8其运行时唯一依赖是核心包tanstack/query-coreworkspace 引用Peer 依赖为preact ^10.0.0。1.2 安装与前置条件从 package.json 可以看到其发布名为tanstack/preact-query属于 ESM 模块type: module并同时提供 modern 与 legacy 两种构建产物与完整类型声明npm install tanstack/preact-query preact # 或使用 pnpm pnpm add tanstack/preact-query preact前提条件需要 Preact 10 及以上版本。包本身sideEffects: false可安全进行 tree-shaking类型层面包内提供了基于 TS 56/57/58/59/6.0/7.0 多版本编译矩阵的类型测试见 package.json 的test:types:*脚本说明其类型定义在多 TS 版本下均被持续验证。1.3 包的导出全景从入口文件 src/index.ts 可以看到该包对外暴露的 API 分为三大部分核心包整体再导出export * from tanstack/query-core因此QueryClient、keepPreviousData、skipToken、dehydrate、hashQueryKey等基础设施全部可用查询类 HooksuseQuery、useInfiniteQuery、useQueries以及配套的queryOptions、infiniteQueryOptions类型化工具Suspense 与预取useSuspenseQuery、useSuspenseInfiniteQuery、useSuspenseQueries、usePrefetchQuery、usePrefetchInfiniteQuery变更类 HooksuseMutation、useMutationState、useIsMutating与mutationOptions基础设施QueryClientProvider/useQueryClient、HydrationBoundary、QueryErrorResetBoundary、useIsFetching、useIsRestoring/IsRestoringProvider。下文将以 README 的 Quick Features 为主线逐项展开并在每节给出对应的源码与测试依据。二、30 秒快速上手仓库中的 examples/preact/simple/src/index.tsx 提供了一个最小可运行示例完整演示了从创建QueryClient、挂载QueryClientProvider到使用useQuery的完整链路import { render } from preact import { QueryClient, QueryClientProvider, useQuery, } from tanstack/preact-query const queryClient new QueryClient() export function App() { return ( QueryClientProvider client{queryClient} Example / /QueryClientProvider ) } const Example () { const { isPending, error, data, isFetching } useQuery({ queryKey: [repoData], queryFn: async () { const response await fetch(https://api.github.com/repos/TanStack/query) return await response.json() }, }) if (isPending) return Loading... if (error ! null) return An error has occurred: error.message return ( div h1{data.full_name}/h1 p{data.description}/p strong {data.subscribers_count}/strong{ } strong✨ {data.stargazers_count}/strong{ } strong {data.forks_count}/strong div{isFetching ? Updating... : }/div /div ) } const app document.getElementById(app) if (!app) throw new Error(Missing #app element) render(App /, app)这段代码里已经蕴含了三个关键点QueryClient是全局数据中心通常在整个应用生命周期内只创建一次QueryClientProvider通过 Context 向子树注入 client——实现见 QueryClientProvider.tsx它还会在挂载/卸载时调用client.mount()/client.unmount()从而订阅窗口焦点、网络在线等全局事件下文第四节详述useQuery的第一个参数是选项对象。这是 v5 起唯一合法的调用形式若传入非对象参数开发环境下 useBaseQuery.ts 会直接抛错提示迁移到单一对象签名。useQuery返回结果中的isPending、isError、isSuccess是status字段pending/error/success派生的布尔标记isFetching则表示即使已有数据展示仍在后台重新获取——这正是 stale-while-revalidate 的直观体现。三、传输层无关的数据获取README 列出的第一条特性是Transport/protocol/backend agnostic data fetching (REST, GraphQL, promises, whatever!)——即数据获取与具体传输协议完全解耦。这体现在类型定义上queryFn被定义为QueryFunction其返回值只需要是一个 PromisePromiseTQueryFnData至于这个 Promise 内部是fetch、axios、GraphQL client 还是纯内存模拟Query 层完全不关心。看 useQuery.ts 的泛型签名useQueryTQueryFnData, TError, TData, TQueryKey(options, queryClient?)TQueryFnDataqueryFn的原始返回类型TData经过select派生后组件实际拿到的数据类型默认为TQueryFnDataTError错误类型默认DefaultError。正因为这一抽象同一个useQuery既可以拉取 REST JSON也可以执行 GraphQL 查询甚至直接解析一个本地 Promise业务组件无需关心底层客户端。此外tanstack/query-core被完整再导出因此queryKey的序列化、queryFn的执行时机都由核心层统一调度多框架React/Solid/Svelte/Vue/Preact共享同一套缓存语义。四、自动缓存 智能重新获取README 的第二条特性是Auto Caching Refetching (stale-while-revalidate, Window Refocus, Polling/Realtime)。这一条值得重点展开因为它是 TanStack Query 体系的核心价值。4.1 stale-while-revalidate先展示旧数据后台再更新只要查询成功过一次结果就会进入QueryCache。之后再次渲染同一个queryKey时如果数据未过期在staleTime之内直接同步返回缓存不发起请求如果数据已过期超过staleTime先立即返回缓存数据保证 UI 不闪白屏同时在后台触发重新获取完成后用新数据驱动重新渲染——这就是isFetching与isPending的区别isPending表示没有任何数据可展示而isFetching表示有数据但在后台刷新。staleTime的默认值为 0即数据一经获取便立即视为过期stale但仍会先展示再刷新将其调大如staleTime: 30_000可显著减少重复请求。4.2 Window Refocus窗口聚焦自动重取当窗口重新获得焦点时Query 会自动重新获取过期的查询。这一机制由两处配合实现QueryClientProvider挂载时调用client.mount()见 QueryClientProvider.tsx订阅全局的 focus/online 事件tanstack/query-core中的focusManager/onlineManager负责事件监听与回调分发其实现位于 packages/query-core/src/focusManager.ts 与 packages/query-core/src/onlineManager.ts。默认行为下用户切走再切回页面时所有 stale 查询会被批量重新验证refetchOnWindowFocus可全局或按查询关闭此行为。4.3 Polling / Realtime轮询与实时刷新通过refetchInterval选项可开启轮询例如refetchInterval: 5_000会让查询每 5 秒自动重新获取一次实现接近实时的数据同步配合refetchIntervalInBackground可控制页面不可见时是否继续轮询。结合上面的窗口聚焦机制可以搭建聚焦即刷新 定时轮询的组合实时方案。4.4 源码视角Observer 与 useSyncExternalStore在 useBaseQuery.ts 中可以观察到上述行为的底层实现const [observer] useState(() new Observer(client, defaultedOptions)) const result observer.getOptimisticResult(defaultedOptions) useSyncExternalStore( useCallback( (onStoreChange) { const unsubscribe shouldSubscribe ? observer.subscribe(notifyManager.batchCalls(onStoreChange)) : noop observer.updateResult() return unsubscribe }, [observer, shouldSubscribe], ), () observer.getCurrentResult(), )每个useQuery在内部对应一个QueryObserver通过useState惰性创建并保持稳定渲染时先调用getOptimisticResult取得乐观结果即使订阅尚未建立也能立刻基于缓存给出数据通过useSyncExternalStore订阅 observer任何缓存变化经notifyManager.batchCalls批量化后触发 Preact 重新渲染useEffect中再调用observer.setOptions(defaultedOptions)同步最新选项。此外默认开启属性级追踪当未显式设置notifyOnChangeProps时返回observer.trackResult(result)组件只会在其实际读取到的属性变化时重渲染从而避免无关更新造成的不必要渲染。查询组件自身的挂载/卸载、缓存驱逐等行为则由QueryCache的订阅机制统一驱动。五、并行查询与依赖查询README 特性第三条Parallel Dependent Queries。5.1 并行查询useQueriesuseQueries用于一次性发起多个相互独立的查询并保持并行执行适合仪表盘等需要同时加载多组数据的场景。它内部使用QueriesObserver统一管理一组子 observer见 useQueries.ts 的导入与 useQueries.test.tsx 的用例。基本用法const results useQueries({ queries: [ { queryKey: [repo, A], queryFn: fetchRepoA }, { queryKey: [repo, B], queryFn: fetchRepoB }, ], })返回的results是一个数组每个元素与useQuery的返回结构一致可单独读取status/data/error。此外该函数还支持元组形式传入每个查询的显式类型参数并有配套的类型级工具QueriesOptions/QueriesResults保证推断出的data类型与每个子查询一一对应。5.2 依赖查询enabled 与 skipToken当某个查询需要依赖另一个查询的结果作为参数时用enabled控制其执行时机即可例如 useQuery.ts 中 JSDoc 给出的经典模式function Post({ postId }: { postId: number | undefined }) { const { data, isLoading, isError, error } useQuery({ queryKey: [post, postId], queryFn: () fetchPost(postId!), enabled: postId ! null, }) if (postId null) return Select a post if (isLoading) return Loading... if (isError) return spanError: {error.message}/span return h1{data?.title}/h1 }要点使用isLoading而非isPending判断加载态——isLoading等价于isPending isFetching查询被禁用disabled时不会误显示加载状态v5 还提供了更类型安全的替代把queryFn传为skipToken如queryFn: postId ! null ? () fetchPost(postId) : skipToken从而免去非空断言postId!编译器能保证queryFn只在postId有值时被调用。注意skipToken模式下refetch()不可用需要手动触发时请改用enabled: false。依赖查询可以进一步串联查询 B 的queryKey中包含查询 A 的data并设置enabled: !!dataA即可实现先取用户、再取该用户的帖子这类链式依赖。六、Mutation 变更与响应式查询重取README 特性第四条Mutations Reactive Query Refetching。查询query负责读取变更mutation负责写入——典型的 create/update/delete 操作或服务端副作用都应走useMutation。6.1 基础用法见 useMutation.ts 的 JSDoc 示例import { useMutation, useQueryClient } from tanstack/preact-query function AddTodo() { const queryClient useQueryClient() const addMutation useMutation({ mutationFn: addTodo, onSuccess: () queryClient.invalidateQueries({ queryKey: [todos] }), }) return ( div {addMutation.isPending ? ( Adding todo... ) : ( {addMutation.isError ? ( divAn error occurred: {addMutation.error.message}/div ) : null} button onClick{() addMutation.mutate(Item)}Add/button / )} /div ) }useMutation返回mutate/mutateAsync两个触发函数以及isPending/isError/error/data等状态。两者的区别mutate(variables, callbacks?)触发后不返回 Promise错误只能通过回调或状态捕获mutateAsync(variables)返回 Promise可用await/try-catch/Promise.all等待结果适合批量提交等场景源码见 useMutation.tsmutate内部实际调用observer.mutate(...)并.catch(noop)吞掉未处理拒绝。6.2 响应式查询重取invalidateQueries 与乐观更新Reactive Query Refetching指的就是变更成功后让相关查询重新获取。最直接的方式是invalidateQueries——把目标查询标记为 stale 并触发重取如上例。更进一步的模式是乐观更新optimistic update在请求发出前先修改本地缓存失败时回滚。这正是仓库中 examples/optimistic-updatesReact 版与 preact 包内 useMutation.test.tsx 所验证的完整链路const addMutation useMutation({ mutationFn: addTodo, onMutate: async (newTodo) { await queryClient.cancelQueries({ queryKey: [todos] }) const previousTodos queryClient.getQueryDataArraystring([todos]) queryClient.setQueryDataArraystring([todos], (old) [ ...(old ?? []), newTodo, ]) // 返回快照失败时用于回滚 return { previousTodos } }, onError: (_err, _newTodo, onMutateResult) { queryClient.setQueryData([todos], onMutateResult?.previousTodos) }, onSettled: () { queryClient.invalidateQueries({ queryKey: [todos] }) }, })回调的语义值得注意源码 JSDoc 有明确说明Hook 级回调传入options的onSuccess/onError/onSettled对每一次mutation 生效每次调用mutate时传入的单次回调只对最近一次调用生效且仅在该组件仍挂载时才会触发——组件卸载会使订阅失效从而阻止这些回调执行。useMutation底层使用MutationObserver并同样通过useSyncExternalStore订阅见 useMutation.ts若设置了throwOnError错误会在渲染阶段被抛出见同文件末尾。七、多层缓存与自动垃圾回收README 特性第五条Multi-layer Cache Automatic Garbage Collection。7.1 多层缓存结构tanstack/query-core将数据存放在多个层级QueryCache保存所有查询的键值状态提供按queryHash查找与全局订阅MutationCache保存所有 mutation 状态useMutationState/useIsMutating正是从它读取全局变更状态每个Query内部维护state.data、state.status、state.fetchStatus、dataUpdatedAt、errorUpdatedAt等字段是缓存的基本单元。这种分层让一个 queryKey 一处缓存、多处组件共享成为可能两个组件使用相同queryKey时共享同一份数据与获取状态不会重复请求。7.2 垃圾回收GC查询在没有活跃订阅者即没有任何挂载的 observer 引用它后进入可回收状态默认gcTimev5 中替代旧的cacheTime为 5 分钟计时结束且期间未重新被订阅时该查询会被从缓存中清除。可全局或按查询调整gcTime例如useQuery({ queryKey: [heavy-data], queryFn: fetchHeavyData, gcTime: 10 * 60 * 1000, // 10 分钟无订阅后回收 })值得注意的是Suspense 模式下 suspense.ts 会对staleTime和gcTime施加下限MIN_SUSPENSE_TIME_MS 1000即至少 1000ms避免组件挂起后重新挂载时触发不必要的立即重取。八、分页查询与游标查询README 特性第六条Paginated Cursor-based Queries。分页有两种常见实现Key-based 分页页码切换把页码放进queryKey每次切换页码就是切换一个新的查询。配合placeholderData: keepPreviousData从tanstack/query-core导出切换页时上一页数据会作为占位数据保留展示isPlaceholderData为true直至新页数据到达页面不会闪空白import { keepPreviousData, useQuery } from tanstack/preact-query import { useState } from preact/hooks function Posts() { const [page, setPage] useState(0) const { data, isPlaceholderData, isError, error } useQuery({ queryKey: [posts, page], queryFn: () fetchPosts(page), placeholderData: keepPreviousData, }) if (isError) return spanError: {error.message}/span return ( div ul {data?.map((post) li key{post.id}{post.title}/li)} /ul button disabled{isPlaceholderData} onClick{() setPage((old) old 1)} Next Page /button /div ) }Cursor-based游标分页使用useInfiniteQuery通过pageParam携带游标如nextId见 useInfiniteQuery.ts 中的完整示例。它支持向前fetchNextPage/hasNextPage与向后fetchPreviousPage/hasPreviousPage两个方向数据以data.pages与data.pageParams两个平行数组组织const { data, isPending, isError, error, fetchNextPage, hasNextPage, isFetching, isFetchingNextPage, } useInfiniteQuery({ queryKey: [projects], queryFn: ({ pageParam }) fetchProjects(pageParam), initialPageParam: 0, getNextPageParam: (lastPage) lastPage.nextId, })useInfiniteQuery的选项与useQuery完全相同仅额外增加initialPageParam、getNextPageParam、getPreviousPageParam、maxPages四个字段其返回结果也等价于useQuery加data.pages、data.pageParams、fetchNextPage、fetchPreviousPage、hasNextPage、hasPreviousPage、isFetchingNextPage、isFetchingPreviousPage。内部实现上它通过useBaseQuery传入InfiniteQueryObserver见 useInfiniteQuery.ts由核心层的InfiniteQueryObserver统一管理分页状态机。源码注释中的提醒命令式分页调用如fetchNextPage可能与默认的重取行为相互干扰导致数据过期。因此建议仅在用户操作触发时调用或加上hasNextPage !isFetching之类的守卫条件。九、加载更多与无限滚动README 特性第七条Load-More Infinite Scroll Queries w/ Scroll Recovery。在第八节useInfiniteQuery的基础上无限滚动只需把点击按钮替换为监听滚动到达底部const sentinelRef useRefHTMLDivElement(null) useEffect(() { const sentinel sentinelRef.current if (sentinel null || !hasNextPage || isFetching) return const observer new IntersectionObserver(([entry]) { if (entry?.isIntersecting) fetchNextPage() }) observer.observe(sentinel) return () observer.disconnect() }, [hasNextPage, isFetching, fetchNextPage])要点在列表末尾放置一个哨兵元素sentinel用IntersectionObserver监测其进入视口只有hasNextPage !isFetching时才建立观察避免滚动到底部后重复触发按钮版则用disabled{!hasNextPage || isFetching}并依据isFetchingNextPage显示 Loading more...这是 useInfiniteQuery.ts JSDoc 提供的两种标准写法。Scroll Recovery滚动恢复指回到之前的页面/列表位置时恢复滚动位置与已加载的分页数据。因为每页数据都以独立 page 缓存配合queryKey的稳定标识框架级路由如 TanStack Router可以轻松恢复状态即使纯手工实现也只需在重建列表后依据已加载 page 数量恢复滚动偏移。十、请求取消README 特性第八条Request Cancellation。当查询因组件卸载、queryKey变化或竞态条件而不需要旧结果时Query 会中止对应的在途请求。queryFn通过AbortSignal感知取消。在 useQuery.ts 与相关类型定义中QueryFunctionContext携带signal字段典型写法useQuery({ queryKey: [posts], queryFn: ({ signal }) fetch(/api/posts, { signal }), })支持AbortSignal的客户端原生fetch、axios 的signal选项等会自动中止网络请求对于无法原生取消的请求可以监听signal的abort事件做清理。取消对用户是无感的——被取消的查询不会进入错误状态也不会污染缓存。需要注意的一个已知取舍源码 useSuspenseQuery.ts JSDoc 明确标注Suspense 模式下取消cancellation不可用使用useSuspenseQuery时应了解这一限制。十一、Preact Suspense 与 Fetch-As-You-Render 预取README 特性第九条Preact Suspense Fetch-As-You-Render Query Prefetching并附注Not recommended because of the bulk preact/compat adds——即该能力依赖preact/compat的 Suspense 实现会引入额外的兼容层体积因此 README 明确提示不推荐在体积敏感的场景使用。11.1 useSuspenseQueryuseSuspenseQuery.ts 是useQuery的 Suspense 变体其实现本质是对useBaseQuery的固定封装return useBaseQuery( { ...options, enabled: true, suspense: true, throwOnError: defaultThrowOnError, placeholderData: undefined, }, QueryObserver, queryClient, )与useQuery的差异集中体现为enabled被强制为truesuspense: true使数据未就绪时渲染被挂起suspends而不是返回pendingthrowOnError使用默认实现defaultThrowOnError见 suspense.ts仅在查询没有缓存数据query.state.data undefined时抛错即首次加载失败抛给错误边界后台刷新失败则继续展示旧数据placeholderData被清空。用法上返回的data保证已定义无需isPending判断错误通过最近的错误边界呈现因此必须把组件包在ErrorBoundary之内并配合QueryErrorResetBoundary实现重试import { Suspense } from preact/compat import { QueryErrorResetBoundary, useSuspenseQuery } from tanstack/preact-query function Posts() { const { data, isFetching } useSuspenseQuery({ queryKey: [posts], queryFn: fetchPosts, }) // data 保证存在 return ( div h1Posts {isFetching ? (refreshing...) : null}/h1 ul {data.map((post) li key{post.id}{post.title}/li)} /ul /div ) } function App() { return ( QueryErrorResetBoundary {({ reset }) ( ErrorBoundary onReset{reset} Suspense fallback{h1Loading posts.../h1} Posts / /Suspense /ErrorBoundary )} /QueryErrorResetBoundary ) }QueryErrorResetBoundary组件及其useQueryErrorResetBoundaryHook 均从本包导出见 src/index.ts对应的错误边界行为由 errorBoundaryUtils.ts 与 QueryErrorResetBoundary.tsx 实现并有 QueryResetErrorBoundary.test.tsx 覆盖。11.2 组件内多个 Suspense 查询的注意点源码 JSDoc 特别提醒在同一个组件里写多个useSuspenseQuery会串行挂起形成请求瀑布waterfall——第一个挂起会阻塞渲染第二个查询直到第一个 resolve 后才开始发起。需要并行时请改用useSuspenseQueries对应导出见 src/index.ts它一次性并发发起多个 Suspense 查询。11.3 Fetch-As-You-Render 预取usePrefetchQueryusePrefetchQuery.tsx 实现了渲染即预取模式在进入Suspense边界之前的父组件渲染期间触发数据获取使子组件挂起后能立刻读到已就绪的数据从而缩短等待时间import { Suspense } from preact/compat import { usePrefetchQuery } from tanstack/preact-query function App() { // 在 Suspense 边界之前于渲染期触发预取 usePrefetchQuery({ queryKey: [posts], queryFn: fetchPosts, }) return ( Suspense fallback{h1Loading posts.../h1} Posts / /Suspense ) }其实现非常精简usePrefetchQuery.tsxif (!client.getQueryState(options.queryKey)) { void client.query(options).catch(noop) }若该queryKey已存在任何缓存状态包括上一次遗留的pending/error状态则跳过预取因此每次渲染调用它都足够廉价不会重复请求已存在或已在途的数据无返回值void只负责点火。配套的usePrefetchInfiniteQuery提供无限查询的渲染期预取。该模式与 Suspense、SSR 水合配合构成 TanStack Query 的数据在渲染前就绪哲学。十二、SSR 水合与持久化虽然不在 README 的 Quick Features 列表中但作为数据层的核心基建值得一提本包导出的HydrationBoundary用于把服务端dehydrate(queryClient)得到的状态注入客户端缓存见 HydrationBoundary.tsx。其关键行为源码注释与 ssr-hydration.test.tsx 均有覆盖新查询在渲染阶段直接水合到缓存保证 SSR 首屏数据在客户端渲染前就位已存在的查询仅在脱水数据更新按dataUpdatedAt比较并考虑带 promise 的流式脱水时于提交后的 effect 中水合避免在过渡transition期间意外覆盖当前页面数据只能水合queries不能水合mutations。此外IsRestoringProvider/useIsRestoring用于持久化恢复期间跳过订阅避免恢复过程中触发不必要重取tanstack/query-persist-client-core则被作为 devDependency 用于相关测试见 fine-grained-persister.test.tsx。十三、专用 DevtoolsREADME 特性最后一条Dedicated Devtools。tanstack/preact-query提供了与框架深度集成的调试工具其源码位于 packages/preact-query-devtools内含基于 Preact 的实现packages/preact-query-devtools/src。Devtools 面板可以查看全部缓存的查询与变更包括queryKey、状态、dataUpdatedAt、fetchStatus逐条检查/刷新/删除缓存条目模拟失焦重取与在线/离线切换定位查询的活跃观察者与最近更新辅助排查重渲染与过期问题。面板与QueryClient的通信同样建立在tanstack/query-core的缓存订阅机制之上因此在本地开发时能直接观察到第四节描述的缓存与重取行为。十四、小结从 README 到源码的能力全景回到 packages/preact-query/README.md 的 Quick Features我们可以把每一条与仓库实现一一对应README 特性对应 Hook / 机制仓库依据Transport agnostic data fetchinguseQueryQueryFunctionuseQuery.ts、src/index.tsAuto Caching RefetchingQueryCache、staleTime、refetchOnWindowFocus、refetchIntervaluseBaseQuery.ts、QueryClientProvider.tsxParallel Dependent QueriesuseQueries、enabled、skipTokenuseQueries.ts、useQuery.tsMutations Reactive RefetchinguseMutation、invalidateQueries、乐观更新useMutation.tsMulti-layer Cache Auto GCQueryCache/MutationCache、gcTimeuseMutationState.tsPaginated Cursor-based QueriesplaceholderData: keepPreviousData、useInfiniteQueryuseInfiniteQuery.tsLoad-More Infinite ScrollfetchNextPageIntersectionObserveruseInfiniteQuery.ts 示例Request CancellationAbortSignaluseQuery.tsPreact Suspense Fetch-As-You-RenderuseSuspenseQuery、useSuspenseQueries、usePrefetchQueryuseSuspenseQuery.ts、usePrefetchQuery.tsx、suspense.tsDedicated Devtoolstanstack/preact-query-devtoolspackages/preact-query-devtools通过上述对照可以看到tanstack/preact-query的所有面向开发者的特性底层都由统一的tanstack/query-core状态机与 observer 订阅模型支撑Preact 层只负责用 Preact 的方式把核心能力暴露为 Hooks。这意味着只要理解了QueryClientqueryKey observer 三元组就能在 Preact 中稳定地构建出可缓存、可取消、可轮询、可无限滚动的数据获取层同时保持组件代码的简洁与声明式。更进一步若你需要把数据方案接入 SSR可结合 HydrationBoundary.tsx 与dehydrate需要持久化时可查看tanstack/query-persist-client-corepackages/query-persist-client-core与对应的 fine-grained-persister.test.tsx 测试用例。【免费下载链接】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),仅供参考