尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

Vue Query 并行查询(Parallel Queries)完整指南:从 useQuery 并排调用到 useQueries 动态并行

Vue Query 并行查询(Parallel Queries)完整指南:从 useQuery 并排调用到 useQueries 动态并行 Vue Query 并行查询Parallel Queries完整指南从 useQuery 并排调用到 useQueries 动态并行【免费下载链接】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 Vue Query 的并行查询能力展开介绍在 Vue 3 组合式 API 场景下如何同时发起多个请求以最大化抓取并发度数量固定的场景直接并排使用useQuery即可数量随渲染动态变化的场景则需要useQueries组合式函数。读完本文你将掌握useQueries的完整参数、响应式与 combine 机制、TypeScript 类型推断技巧以及其底层QueriesObserver的实现原理。什么是并行查询并行查询Parallel Queries指在同一时间同时执行的查询目的是让多个相互独立的数据请求并发发起从而最大化抓取并发度避免串行等待造成的整体加载时间拉长。在 Vue Query 中实现并行查询有两种方式手动并行直接并排使用多个useQuery或useInfiniteQuery组合式函数动态并行使用useQueries组合式函数根据运行时数据动态生成任意数量的查询。本指南对应的 Vue 端核心文档为 docs/framework/vue/guides/parallel-queries.md其内容来源于 React 侧的官方指南 docs/framework/react/guides/parallel-queries.md并在 Vue 响应式体系下做了适配。手动并行查询数量固定时的最简单方案当并行查询的数量在运行期间保持不变时使用并行查询不需要任何额外工作——只需并排使用任意数量的useQuery或useInfiniteQuery即可。以下是一个标准的 Vue 3script setup示例script setup langts // The following queries will execute in parallel const usersQuery useQuery({ queryKey: [users], queryFn: fetchUsers }) const teamsQuery useQuery({ queryKey: [teams], queryFn: fetchTeams }) const projectsQuery useQuery({ queryKey: [projects], queryFn: fetchProjects, }) /script这三个查询在组件创建时会被同时发起互不阻塞。useQuery的签名定义于 packages/vue-query/src/useQuery.ts它接收一个UseQueryOptions其中queryKey支持MaybeRef其余选项大多支持MaybeRefDeep返回响应式的查询状态。由于 Vue 的setup()每个组件实例只执行一次这种并排写法天然安全不存在 hooks 规则 的限制。Suspense 模式提示在 React Query 的 Suspense 模式下这种并排写法会因为第一个查询抛出 Promise 挂起组件而失效需要改用useSuspenseQueries。在 Vue 侧useQuery本身是同步返回响应式状态、不依赖 Suspense 抛 Promise 的机制因此该限制主要影响 React 生态如果使用 Vue 的Suspense组合异步组件仍建议让每个查询组件各自独立避免整体挂起。动态并行查询数量可变时使用 useQueries如果需要的查询数量会随渲染状态变化例如来自接口返回的用户列表每个用户要拉取一份详情就不能再手写固定数量的useQuery。Vue Query 提供了useQueries组合式函数可以动态地并行执行任意数量的查询且完全遵循 Vue 的响应式体系。useQueries接收一个选项对象其中包含一个queries 键其值是一个查询对象数组它返回一个只读 ref.value是查询结果数组顺序与输入顺序一致script setup langts import { computed } from vue const users computed(...) const queries computed(() users.value.map(user { return { queryKey: [user, user.id], queryFn: () fetchUserById(user.id), } }) ); const userQueries useQueries({queries: queries}) /script上面的例子中users变化后queries这个 computed 会重新求值useQueries会立刻为新生成的每个用户查询对象创建对应的查询并并行发起请求返回的userQueries数组也会同步更新——这正是动态并行查询的核心价值。参数详解根据 Vue 侧参考文档 docs/framework/vue/reference/useQueries.md 与实现源码useQueries接受如下选项选项类型说明queries(() MaybeRefDeepUseQueriesOptions) \| MaybeRefDeepUseQueriesOptions查询对象数组或返回数组的函数数组内每个元素的选项与useQuery的选项一致但不包含queryClient它需要在顶层单独传入combine(result: UseQueriesResults) TCombinedResult可选。将多个查询结果合并为单个值返回queryClientQueryClient第二个参数。传入自定义QueryClient否则使用最近上下文中的客户端需要注意placeholderDatauseQueries同样支持placeholderData选项但它不像useQuery那样能拿到上一次渲染的查询结果作为占位因为每次渲染传入的查询数量可能不同无法建立一一对应的映射关系。重复 queryKey 警告如果查询对象数组中同一个 queryKey 出现多次可能会导致数据在查询之间共享去重合并。需要去重时应先对查询做去重再手动把结果映射回期望的结构。源码层面的响应式实现useQueries的实现位于 packages/vue-query/src/useQueries.ts其核心流程如下响应式解析查询列表用一个computed对queries求值——支持函数形式() queries和 ref 形式unref顶层数组并对每个查询对象调用cloneDeepUnref深层解包其中的 ref如果enabled是函数getter则在此处立即调用取值。统一默认选项每个查询对象都经过client.defaultQueryOptions(clonedOptions)处理补全默认的staleTime、retry、refetchOnWindowFocus等配置并设置_optimisticResults。委托给 QueriesObserver创建一个来自tanstack/query-core的QueriesObserver订阅后每次状态变化都会更新内部的shallowRef状态。监听变化通过watch(defaultedQueries, ...)在查询列表变化时调用observer.setQueries(...)并刷新乐观结果通过onScopeDispose在组件卸载时取消订阅避免内存泄漏。返回只读 ref根据options.shallow决定返回shallowReadonly(state)还是readonly(state)。此外在开发模式下如果在setup()或运行中的 effect scope 之外调用useQueries源码会打印警告vue-query composable likeuseQuery()should only be used inside asetup()function or a running effect scope. They might otherwise lead to memory leaks.。对应的测试用例见 packages/vue-query/src/tests/useQueries.test.ts。返回结果与单独 refetchuseQueries返回的数组中每个元素都是标准查询结果QueryObserverResult包含status、data、error、isPending、isFetching、isStale等字段并且每个结果还挂载了独立的refetch方法。从源码 packages/vue-query/src/useQueries.ts 可以看到refetch会通过observer.getOptimisticResult定位到对应下标的查询再调用其query.refetch——也就是说可以只重拉某一个查询而不影响其他并行查询。测试用例 packages/vue-query/src/tests/useQueries.test.ts 验证了这一点对queriesState.value[0].refetch()后只有第 0 个查询的数据更新第 1 个查询的数据保持不变。响应式更新与 getter 支持useQueries的queries选项支持多种响应式形态测试用例覆盖了ref 数组queries ref([...])修改queries.value如 splice 替换后useQueries会同步返回新查询列表对应的结果见 测试用例queryKey 中的 getterqueryKey 内可以嵌入() ref.value形式的 getterref 变化时自动触发重新抓取任意深度嵌套 getterqueryKey 中支持任意嵌套的 ref / getter 组合数组、对象、函数均可options getter 函数queries: () [...]函数形式同样具备响应式。这些能力源于MaybeRefDeep类型与cloneDeepUnref实现保证了 Vue 生态中ref 即响应式来源的使用习惯在并行查询中完全成立。使用 combine 合并查询结果如果希望把多个查询的data或其他信息合并成单个值返回可以使用combine选项const ids [1, 2, 3] const combinedQueries useQueries({ queries: ids.map((id) ({ queryKey: [post, id], queryFn: () fetchPost(id), })), combine: (results) { return { data: results.map((result) result.data), pending: results.some((result) result.isPending), } }, })上述示例中combinedQueries.value是一个包含data和pending两个属性的对象。注意所有其他查询结果属性如error、isFetching等都会丢失需要什么就在combine返回值中显式保留。从 Vue 侧参考文档 docs/framework/vue/reference/useQueries.md 可知combine的结果会进行结构共享structural sharing尽可能保持引用稳定。底层实现在 packages/query-core/src/queriesObserver.tscombine只在以下情况重新执行——combine函数本身引用发生变化任意一个查询结果发生变化。Vue 中的 memoization 说明与 React 不同Vue 的setup()函数每个组件实例只运行一次因此上面这种内联定义的combine函数在响应式更新期间已经拥有稳定引用无需额外的 memoization。直接内联即可享受结构共享带来的引用稳定性收益。测试用例 packages/vue-query/src/tests/useQueries.test.ts 验证了combine行为两个查询成功后queriesResult.value等于{ combined: true, res: [firstResult, secondResult] }。TypeScript内联 select 的类型推断限制与解决与useQuery不同useQueries无法从同一个查询对象中的queryFn推断出内联select的data参数类型。原因在于useQueries一次性推断整个queries数组的类型内联写在对象字面量里的select无法从同对象的queryFn获得上下文类型因此回退为unknown这是 TanStack Query 已知的 TypeScript 限制。useQueries({ queries: [ { queryKey: [post, 1], queryFn: () fetchPost(1), // ❌ 这里的 data 是 unknown select: (data) data.title, }, ], })官方提供两种解决方案方案一显式标注select参数类型useQueries({ queries: [ { queryKey: [post, 1], queryFn: () fetchPost(1), // ✅ 这里的 data 是 Post select: (data: Post) data.title, }, ], })方案二先用queryOptions定义查询再传入useQueriesqueryOptions帮助函数会在单个对象内部先解析好类型再交给useQueriesconst postOptions (id: number) queryOptions({ queryKey: [post, id], queryFn: () fetchPost(id), // ✅ 这里的 data 是 Post select: (data) data.title, }) useQueries({ queries: [postOptions(1), postOptions(2)] })同样的限制也适用于展开覆盖对queryOptions结果做展开spread再覆盖select时覆盖的select依然会回退为unknownuseQueries({ queries: [ { ...postOptions(1), // ❌ 这里的 data 是 unknown select: (data) data.title, }, ], })解决办法是再次用queryOptions包裹展开结果让覆盖发生在类型解析之前useQueries({ queries: [ queryOptions({ ...postOptions(1), // ✅ 这里的 data 是 Post select: (data) data.title, }), ], })类型层面的实现佐证useQueries的类型系统相当严谨见 packages/vue-query/src/useQueries.tsUseQueriesOptions会递归地逐项解包查询对象推断并强制校验泛型参数queryFnData、error、data、queryKey并设置MAXIMUM_DEPTH 20防止大型数组字面量触发 TS 深度限制UseQueriesResults递归地把每个选项映射为对应的QueryObserverResult并通过GetDefinedOrUndefinedQueryResult处理initialData的有无从而区分DefinedQueryObserverResult与普通QueryObserverResult这两个工具类型均从 packages/vue-query/src/index.ts 导出供库使用者组合自己的类型。这意味着使用queryOptions或元组显式标注如[TQueryFnData, TError, TData]时返回的结果数组类型也能被精确推导。底层原理QueriesObserver 如何调度并行查询useQueries的上层是 Vue 响应式封装真正负责调度查询的是tanstack/query-core中的QueriesObserver实现位于 packages/query-core/src/queriesObserver.ts。从源码结构看它的工作方式可以概括为构造时接收查询数组为每个查询创建独立的QueryObserver并分别订阅其状态变化见 queriesObserver.ts提供setQueries方法在查询列表变化时增量同步复用 queryKey 未变的 observer销毁移除的 observer为新查询创建 observer见 queriesObserver.ts提供getOptimisticResult以支持渲染期乐观结果在 Vue 中用于shallowRef的初始值与订阅后的首帧同步见 queriesObserver.tscombine逻辑在 observer 内部完成结构共享与replaceEqualDeep去重保证引用稳定性见 queriesObserver.ts。由于每个查询都有独立的QueryObserver所以各个并行查询之间互不干扰一个查询失败、重试或重新抓取都不会影响其他查询的状态机。测试用例 packages/vue-query/src/tests/useQueries.test.ts 展示了一个查询 error、另一个查询 success的结果数组形态正是这种隔离性的直接体现。实践建议与常见误区数量固定优先手动并行固定数量时直接并排写useQuery代码可读性最好且不引入额外的数组解构心智负担。数量动态必须用useQueries查询列表来自运行时数据如列表页勾选、用户列表详情时用queries选项接收 computed / ref / 函数形式让 Vue 响应式驱动查询集合的增删。善用combine聚合状态当 UI 需要全部加载完成或存在失败这类聚合信号时用combine一次性推导避免在模板中反复some/every。警惕重复 queryKey不要在queries数组中重复使用相同 queryKey否则数据会在查询之间共享导致结果结构不符合预期。注意select类型回退涉及内联select时要么显式标注参数类型要么统一用queryOptions定义后再传入useQueries保持类型安全。只在 setup 作用域内调用开发模式下在setup()或 effect scope 之外调用useQueries会收到内存泄漏警告生产环境则不做检查——请务必在组合式函数或组件内调用。总结并行查询是 Vue Query 处理同时发起多个独立请求场景的标准方案固定数量用useQuery并排声明动态数量用useQueries响应式驱动。useQueries在 Vue 中拥有完整的响应式支持——ref 数组、getter queryKey、options 函数形式皆可响应配合combine做结果聚合、queryOptions解决类型推断问题再结合底层QueriesObserver的增量调度机制足以支撑从仪表盘多接口聚合到列表详情批量加载等各类并发数据需求。延伸阅读Vue Query 概览 · useQuery 参考 · useQueries 参考 · queryOptions 参考【免费下载链接】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),仅供参考
返回列表