@tanstack/preact-query 的 QueryClientProvider:让 Preact 应用全局共享 QueryClient 的根组件

@tanstack/preact-query 的 QueryClientProvider:让 Preact 应用全局共享 QueryClient 的根组件 tanstack/preact-query 的 QueryClientProvider让 Preact 应用全局共享 QueryClient 的根组件【免费下载链接】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/queryQueryClientProvider 是tanstack/preact-query中把QueryClient实例注入 Preact 组件树的标准入口它在组件挂载与卸载时分别调用client.mount()/client.unmount()从而把客户端订阅到 focus / online 事件。读完本文你将掌握 QueryClientProvider 的完整使用姿势、props 语义、基于 Context 的传递机制以及它与useQueryClient、useQuery等 Hook 协同工作时的注意事项。一、QueryClientProvider 是什么在tanstack/preact-query的架构中QueryClient负责管理查询缓存QueryCache、变更缓存MutationCache与各类默认选项是整个数据获取体系的中枢对象。为了让组件树中任意层级的useQuery、useMutation、useQueryClient等 Hook 都能访问到同一个客户端需要把QueryClient放到 Preact 的 Context 中——这正是QueryClientProvider的职责。官方参考文档 QueryClientProvider.md 给出了其函数签名function QueryClientProvider(__namedParameters): VNode;组件接收一个名为client的必填属性把传入的children包裹在上下文 Provider 中返回使子树内的所有 Hook 都能通过useQueryClient读取到这个QueryClient实例。该组件的类型定义与实现位于 QueryClientProvider.tsx与 React 版 react-query/src/QueryClientProvider.tsx、Solid 版 solid-query/src/QueryClientProvider.tsx 保持同构的设计——它属于框架适配层真正的心智模型是全局唯一客户端 上下文注入。二、props 语义client 与 childrenQueryClientProvider接受的属性由类型别名QueryClientProviderProps定义其完整声明见 QueryClientProviderProps.md 与源码 QueryClientProvider.tsxexport type QueryClientProviderProps { /** * **Required** * * The QueryClient instance to provide. */ client: QueryClient /** * The components that get access to the provided QueryClient. */ children?: ComponentChildren }两个属性含义如下属性类型必填说明clientQueryClient是要向下注入的QueryClient实例通常由new QueryClient()创建childrenComponentChildrenPreact 组件子节点类型否可以读取该QueryClient的组件子树注意children类型来自 Preact 自身的ComponentChildren意味着它可以是单个 VNode、组件数组、文本节点等 Preact 合法子内容。三、最小可用示例参考文档中给出的最简用法如下这也是绝大多数应用的标准起步写法import { QueryClient, QueryClientProvider } from tanstack/preact-query const queryClient new QueryClient() function App() { return QueryClientProvider client{queryClient}.../QueryClientProvider }queryClient通常被创建在组件外部模块级作用域从而保证整个应用生命周期内复用同一个实例避免每次渲染重新创建导致缓存丢失。仓库自带的真实可运行示例 examples/preact/simple/src/index.tsx 展示了完整用法创建全局queryClient用QueryClientProvider包裹App /子组件内部通过useQuery请求 GitHub 仓库信息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 ) }该示例同时演示了三个要点Provider 位于组件树根部、业务组件无需手动传递客户端、子组件直接消费全局 client 发起的查询状态。想了解组件树应如何组织可结合 preact 快速上手文档 阅读。四、源码视角Provider 内部做了什么只看 API 文档容易把QueryClientProvider当作一个无脑透传的包裹组件。但阅读其实现 QueryClientProvider.tsx 会发现它在挂载阶段承担了两个关键职责export const QueryClientProvider ({ client, children, }: QueryClientProviderProps): VNode { useEffect(() { client.mount() return () { client.unmount() } }, [client]) return ( QueryClientContext.Provider value{client} {children} /QueryClientContext.Provider ) }4.1 生命周期绑定mount / unmount组件挂载后通过useEffect立即调用client.mount()并利用 Preact Hook 的清理函数在卸载时调用client.unmount()。effect 的依赖数组是[client]也就是说当传入的client实例发生变化时旧客户端会被正确卸载、新客户端会被挂载——这为运行时热切换客户端提供了保证。官方参考文档 QueryClientProvider.md 对这套行为给出的说明是当应用重新获得焦点或恢复在线时客户端会恢复所有被暂停paused的 mutation并按需重新拉取数据。4.2 mount / unmount 的底层实现QueryClient.mount()/QueryClient.unmount()定义在 query-core 的 queryClient.tsmount(): void { this.#mountCount if (this.#mountCount ! 1) return this.#unsubscribeFocus focusManager.subscribe(async (focused) { if (focused) { await this.resumePausedMutations() this.#queryCache.onFocus() } }) this.#unsubscribeOnline onlineManager.subscribe(async (online) { if (online) { await this.resumePausedMutations() this.#queryCache.onOnline() } }) } unmount(): void { this.#mountCount-- if (this.#mountCount ! 0) return this.#unsubscribeFocus?.() this.#unsubscribeFocus undefined this.#unsubscribeOnline?.() this.#unsubscribeOnline undefined }从源码可以提炼出三个值得注意的实现细节订阅 focus 与 online 事件mount()会向focusManager与onlineManager订阅事件。窗口重新聚焦时执行恢复暂停的 mutation queryCache.onFocus()网络重新在线时执行恢复暂停的 mutation queryCache.onOnline()这正是 Provider 能让查询在切回标签页 / 恢复网络后自动刷新的根本原因。引用计数防抖#mountCount字段保证同一个 client 被多个 Provider 同时挂载时底层事件订阅只建立一次全部卸载后才真正取消订阅。这意味着你可以安全地在一个应用中嵌套多个QueryClientProvider而不会重复注册监听器。幂等安全重复调用mount()在已挂载状态下再次调用不会重复订阅重复unmount()也不会在下溢时出错边界处理集中在 count 判断上。这些细节解释了为什么文档强调由 Provider 负责调用client.mount()/client.unmount()——开发者不需要也不应该手动调用这两个方法。五、通过 useQueryClient 消费上下文Provider 注入的客户端通过一个模块级导出的 Context 来传递其定义同样位于 QueryClientProvider.tsxexport const QueryClientContext createContextQueryClient | undefined( undefined, )配套的 Hook 是 useQueryClient.md 中描述的useQueryClient实现见 QueryClientProvider.tsxexport const useQueryClient (queryClient?: QueryClient) { const client useContext(QueryClientContext) if (queryClient) { return queryClient } if (!client) { throw new Error(No QueryClient set, use QueryClientProvider to set one) } return client }useQueryClient的取值优先级为显式传入的可选参数queryClient用于强制使用某个自定义客户端否则返回 Context 中最近一层的QueryClient如果组件树中根本没有QueryClientProvider会抛出错误No QueryClient set, use QueryClientProvider to set one。这一行为意味着useQuery、useMutation等 Hook 一旦脱离 Provider 使用会直接报错。在实际项目中这通常发生在把查询 Hook 用到了被渲染在 Provider 外部的组件、Portal、独立挂载的弹层里——排查时优先检查组件树位置即可。由该源码可推断一个重要能力由于 Preact Context 支持嵌套覆盖你完全可以在应用中用多个QueryClientProvider形成部分隔离的区域让特定子树使用不同的缓存与配置例如管理后台使用独立 client。useQueryClient的可选参数则为绕过 Context、显式指定客户端提供了逃生通道这在编写组件库、测试夹具时尤其有用。六、与其他数据源 Provider 的关系除了QueryClientProvidertanstack/preact-query还暴露了管理恢复状态的上下文组件例如 IsRestoringProvider 与配套的useIsRestoringHook以及用于 SSR / 持久化场景的 HydrationBoundary。它们的共性是通过 Preact Context 把基础设施对象QueryClient、恢复标记、水合数据注入组件树再由上层查询 Hook 消费。在项目中的典型组装顺序通常为QueryClientProvider client{queryClient} IsRestoringProvider value{isRestoring} {/* 应用的其余组件树 */} /IsRestoringProvider /QueryClientProvider关于其余全部公开函数与变量的完整索引可查阅 preact 参考索引。七、最佳实践小结结合官方文档、源码与示例在实际项目中推荐遵循以下约定全局单例const queryClient new QueryClient()写在模块顶部随应用进程复用避免组件内反复new。挂在最根部把QueryClientProvider放在 App 根节点附近保证所有需要查询能力的子树都能取到客户端。不要手动 mount/unmount生命周期由 Provider 的useEffect托管手写调用只会造成重复订阅或内存泄漏。缺失 Provider 的错误处理牢记useQueryClient在无 Provider 时会 throw用错误栈定位脱离 Provider 的查询 Hook。多实例场景利用嵌套需要隔离缓存时嵌套多层 Provider底层 count 机制保证不会重复订阅全局事件。想深入了解QueryClient的完整 API缓存管理、默认选项、resumePausedMutations等可直接阅读 query-core 的 QueryClient 类源码它是 Provider 所注入对象的全部能力来源。【免费下载链接】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),仅供参考