Apollo Vue 查询状态模型:深入解析 @vue/apollo-composable 的 Current 接口 前端GraphQL【免费下载链接】apollo Apollo/GraphQL integration for VueJS项目地址https://gitcode.com/gh_mirrors/apollo2/apollo点击查看免费下载导读Current是vue/apollo-composable中useQuery返回的判别联合discriminated union状态类型它把本次查询的结果数据与本次请求的网络状态统一收口到一个响应式对象里让result、resultState、loading、networkStatus、pending、isPreviousResult、error七个字段可以在模板和 TS 中同时完成类型收窄与 UI 分支渲染。本文以 Current.md 为骨架结合 useQuery 实现源码 与 useQuery 测试用例完整拆解每个字段的语义、取值来源与底层状态机帮助你准确判断数据从哪来、请求处于什么阶段并正确使用returnPartialData、keepPreviousResult、debounce/throttle等联动选项。读完本文你将能熟练读写current并在模板中写出不会踩坑的加载、空态、错误与过期数据分支。一、Current 是什么一接口两类信息从类型定义看Current是由 Apollo 上报的结果状态与 Vue-Apollo 自建状态合并而成的// packages/vue-apollo-composable/src/useQuery.ts export type CurrentTData, TStates ResultStateTData, TStates VueApolloState其中ResultState把 Apollo ClientObservableQuery.Result中的data/dataState重命名为 Vue-Apollo 风格的result/resultState见 useQuery.ts 与toResultState辅助函数VueApolloState则是 Vue-Apollo 自己跟踪的pending与isPreviousResultuseQuery.ts。文档将全部字段分成两组分组字段描述对象1. Operation dataerror?、isPreviousResult、partial已废弃、result、resultState数据本身查询返回了什么、完整与否、来自哪一组变量2. Network infoloading、networkStatus、pending请求本身有没有请求在飞、处于防抖/节流窗口还是已发出理解这条分界线是正确使用current的关键result相关的字段描述你正在展示的数据loading/networkStatus/error描述正在替换它的请求。isPreviousResult存在的原因正是为了让这两组信息可以同时成立见后文第五节。在useQuery的返回对象中current是以ReadonlyRefCurrentTData, TStates形式暴露的响应式状态useQuery.ts模板里直接读写current.loading、current.resultState即可无需手动解包。二、Operation data查询结果说了什么2.1 result查询完成后的数据对象result: object | null | undefinedresult存放 GraphQL 查询完成后返回的数据对象。文档特别提醒当查询产生一个或多个错误时result可能为undefined——具体行为取决于查询的errorPolicy选项errorPolicy: none默认结果中包含错误信息但不包含部分结果此时result通常为undefinederrorPolicy: all同时返回错误与部分数据errorPolicy: ignore忽略错误直接使用部分数据。在 Options 接口 中可以看到该选项的完整说明。与useLazyQuery的FetchMoreResult一样这里遵循 Vue-Apollo 的命名惯例Apollo 里的data在 Vue-Apollo 中一律叫result。2.2 resultState结果的完整度判别器resultState: complete | partial | empty | streamingresultState是Current的判别字段discriminator它精确描述result的完整程度四个取值互斥取值含义result状态empty缓存未能满足任何数据或结果不完整undefinedpartial缓存满足了部分字段但结果仍不完整部分数据仅在returnPartialData: true时可能出现streaming因defer/stream延迟查询数据仍在陆续到达不完整但持续增长complete结果已完全满足来自缓存或网络完整数据这四个取值正是 streaming 文档 中defer查询生命周期的基础先empty第一块数据到达后变streaming服务端宣告结束才变complete。resultState最重要的价值是类型收窄。因为result在empty时是undefined只有借助判别联合才能让 TS 推断出安全的数据类型这也是官方推荐读取result一律走current的原因queries 文档const { current } useQuery(GetUser) if (current.value.resultState complete) { // 此处 current.value.result 被收窄为 TData可安全访问嵌套字段 console.log(current.value.result.user.name) }在模板中同样可以按resultState分支渲染测试用例里也验证了这一模式useQuery.test.tsdiv v-ifcurrent.loadingLoading.../div div v-else-ifcurrent.resultState complete {{ current.result.hello }} /div2.3 partial已废弃的兼容字段/** deprecated */ partial: booleanpartial描述result是完整结果还是部分结果仅在returnPartialData: true时才会被置位。文档明确标注该字段将在 Apollo Client 的未来版本中被移除其职能已由更精确的resultStatepartial取值完全取代。新代码应直接使用resultState partial判断不要依赖partial。2.4 error最近一次执行的错误error?: ErrorLike单个ErrorLike对象描述最近一次查询执行期间发生的错误。它与resultState的联动语义值得注意errorPolicy: none时出错会让result变为undefined而isPreviousResult: true的保留结果场景中error描述的是正在替换旧数据的那次请求详见第五节。从源码实现看error通过currentState统一维护useQuery.ts并在applyState保留结果时被特殊处理只有新状态确实携带error时才覆盖旧值useQuery.ts。三、Network info请求本身处于什么阶段3.1 loading查询是否忙loading: booleanloading为true表示查询处于忙碌状态。文档给出的定义比直觉更宽它覆盖三个时间段请求在飞request in flight新变量正在等待debounce/throttle定时器两者之间的交接期变量已被接受、请求尚未发出的瞬间。因此loading比networkStatus 7更宽泛——后者只描述请求本身。源码中的实现印证了这一点// packages/vue-apollo-composable/src/useQuery.ts const loading computed(() pending.value || isCommitting.value || currentState.value.loading)loading由三部分合成pending防抖/节流等待窗口、isCommitting变量已提交但还没进入下一次刷新、以及 Apollo 上报的loading。这意味着只要变量发生变化loading立刻为true搜索框打字即显示 spinner而不用等防抖结束queries 文档。3.2 pending防抖/节流窗口的专属标志pending: booleanpending为true表示variables已变化、请求已承诺committed发出但因debounce或throttle选项尚未真正发到网络。loading虽然也覆盖这个窗口但pending让你能区分定时器还没走完与请求真的在线上——例如做请求指标统计、展示取消按钮等场景。源码中pending的实现非常直接// packages/vue-apollo-composable/src/useQuery.ts const pending computed(() { const { debounce, throttle } vueApolloQueryOptions.value if (debounce null throttle null) return false return !equal(variables.value, currentVariables.value) })只有配置了debounce或throttle时pending才可能为true且深等比较wry/equality的equal保证重建出深等内容的变量不会报为 pending因为没有请求会发出在定时器走完前变回去的变量同样不会报为 pendingqueries 文档。注意一个细节pending为true期间networkStatus仍保持ready——网络状态只描述网络本身。这是文档明确强调的it staysreadywhilependingistrue。3.3 networkStatus底层网络状态码networkStatus: NetworkStatus数字型网络状态码描述查询关联请求当前的网络阶段可能取值见 Apollo Client 的networkStatus.ts。典型取值包括状态含义ready空闲idle可能刚完成或尚未开始loading初次加载中refetch重新请求中networkStatus 7时loading为真poll轮询中fetchMore分页加载更多中streaming增量传输中networkStatus与pending互补它只描述网络在pending为true期间保持ready。文档建议它与notifyOnNetworkStatusChange选项配合使用——开启该选项后网络状态每次变化都会触发新的状态事件Options 文档模板中即可区分初次加载与刷新中div v-ifcurrent.networkStatus NetworkStatus.refetch Refetching... /div四、source 视角Current 状态机是如何被驱动的理解了字段语义后再看 useQuery.ts 内部如何生产这些字段能避免很多使用陷阱。4.1 单一状态源currentState所有 Operation data 与 Apollo 上报的网络字段先汇总进一个shallowRef// packages/vue-apollo-composable/src/useQuery.ts const currentState shallowRefuseQuery.ResultStateTData PickuseQuery.VueApolloState, isPreviousResult({ result: undefined, loading: false, networkStatus: NetworkStatus.ready, resultState: empty, partial: false, isPreviousResult: false, })current计算属性在其上叠加pending与合成后的loading并通过isSameState做对象身份复用当没有任何字段实际变化时返回上一次的对象避免watch(current)和onNextState误报变化[useQuery.ts](https://link.gitcode.com/i/773228f6a9418d2a913f4001e13a2b67#L945-L950, L1182-L1196)。4.2 Apollo 状态进入 Vue 的桥applyStateObservableQuery 的每次通知都会经过toResultState改名后进入applyStateuseQuery.ts。该函数承担keepPreviousResult的核心逻辑if ( newState.resultState empty vueApolloQueryOptions.value.keepPreviousResult previousState.resultState ! empty ) { // 保留旧 result / resultState / partial覆盖 loading / networkStatus / error currentState.value { ...retainedResult, ...(newState.error ! undefined { error: newState.error }), loading: newState.loading, networkStatus: newState.networkStatus, isPreviousResult: true, } return } currentState.value { ...newState, isPreviousResult: false }这正是第五节要展开的核心机制保留结果时result、resultState、partial三个字段整体保持旧值所以按resultState收窄永远安全而loading、networkStatus、error来自新请求。4.3 响应式选项的分流源码将选项拆成两部分分别响应useQuery.tsApollo 原生选项fetchPolicy、errorPolicy、returnPartialData、pollInterval、notifyOnNetworkStatusChange等进入watchQueryOptions最终随apolloWatchQueryOptions传给client.watchQuery或触发reobserveVue-Apollo 专属选项clientId、enabled、throttle、debounce、prefetch、keepPreviousResult、awaitComplete进入vueApolloQueryOptions直接驱动pending、loading、applyState等内部逻辑。debounce/throttle通过useDebounceFn/useThrottleFn实现变量变化被 watch 捕获后按配置分流提交useQuery.ts。测试用例验证了两种行为debounce时快速连续更新只会发出最后一次Rapid updates - only last should go through after debouncethrottle则按 leading trailing 边沿发出useQuery.test.ts。五、实战聚焦isPreviousResult 与 keepPreviousResult5.1 语义旧数据与替换请求并存isPreviousResult: boolean当keepPreviousResult: true时变量变化后的新请求在途期间result会保留上一组变量的数据。此时resultState、result、partial描述被保留的旧数据——因此按resultState收窄永远安全loading、networkStatus、error描述正在替换它的新请求isPreviousResult: true让你能区分这是不是新数据。文档强调narrowing onresultStateis always safe因为保留逻辑保证result/resultState/partial三者同步移动见 4.2 的applyStateisPreviousResult只负责标注来源。5.2 典型模板写法从 queries 文档 的示例可以看到推荐用法——给旧数据加过期样式script setup langts const term ref() const { current } useQuery(SearchProducts, { variables: { term }, keepPreviousResult: true, }) /script template ul v-ifcurrent.resultState complete :class{ stale: current.isPreviousResult } li v-forproduct in current.result.products :keyproduct.id {{ product.name }} /li /ul p v-else-if!current.loadingNo products found./p /template这一模式对筛选器、分页尤其有价值每次变量变化不再闪空态而是继续展示旧数据直到新数据到达。测试用例完整覆盖了状态迁移useQuery.test.ts首次查询完成resultState complete、isPreviousResult false改变变量后立即result仍是first、resultState仍为complete、isPreviousResult true、loading true新数据到达isPreviousResult翻回false模板渲染second。5.3 与 await 的联动useQuery返回PromiseLikethen方法用isAwaited判定何时可以 resolveuseQuery.ts保留结果不属于当前变量因此isPreviousResult: true时不会提前 resolveawait 会一直等到真正针对当前变量请求的数据到达。这保证了await useQuery()与Suspense组合时不会拿到上一组变量的过期数据。六、完整字段速查表与联动选项6.1 Current 字段速查字段类型分组一句话语义resultobject \| null \| undefinedOperation data查询完成后的数据出错时按errorPolicy可能为undefinedresultStatecomplete \| partial \| empty \| streamingOperation data判别器描述result完整度用于 TS 收窄partialbooleanOperation data已废弃仅returnPartialData: true时置位用resultState替代error?ErrorLikeOperation data最近一次执行的错误isPreviousResultbooleanOperation data结果是否来自上一组变量keepPreviousResultloadingbooleanNetwork info忙碌请求在飞 防抖/节流窗口 交接期pendingbooleanNetwork info变量已提交但请求尚未发出仅配置debounce/throttle时networkStatusNetworkStatusNetwork info网络状态码pending期间保持ready6.2 影响 Current 的关键选项选项默认值影响的字段说明returnPartialDatafalseresultState、partial允许从缓存返回部分数据resultState才会出现partialerrorPolicynoneresult、error决定出错时是否携带部分结果keepPreviousResultfalseisPreviousResult、result、resultState新请求在途时保留旧结果并标记isPreviousResult: truedebounce/throttle无pending、loading变量更新的延迟窗口二者互斥notifyOnNetworkStatusChange无networkStatus事件网络状态每次变化都触发新状态事件awaitCompletefalse配合resultState streamingawait useQuery()是否等待完整数据用于defer/stream以上选项的完整定义见 Options 接口文档默认值均可在源码的Base.VueApolloOptions与Base.Options注释中核对useQuery.ts。6.3 组合案例一个完整的查询状态分支综合所有字段一个健壮的模板分支可以这样组织script setup langts const { current } useQuery(GetPosts, { variables: { term }, debounce: 300, keepPreviousResult: true, }) /script template !-- 防抖窗口 请求在飞 交接期都算 loading -- div v-ifcurrent.loading current.resultState emptyLoading.../div !-- 保留旧数据时展示并标记过期 -- div v-else-ifcurrent.resultState complete :class{ stale: current.isPreviousResult } p v-ifcurrent.pending正在等待防抖…/p ul li v-forpost in current.result.posts :keypost.id{{ post.title }}/li /ul /div div v-else-ifcurrent.error{{ current.error.message }}/div div v-elseNo results./div /template七、延伸阅读useQuery 接口总览Current所属命名空间的全部接口与类型别名Queries 指南useQuery基础用法、变量响应式、缓存与 fetch policyLoading States跨多个查询聚合loading的useQueryLoading/useGlobalQueryLoading等组合式函数Streaming deferresultState streaming的完整生命周期与awaitComplete用法实现源码currentState、applyState、pending、loading与isAwaited的具体实现测试用例覆盖keepPreviousResult、returnPartialData、debounce/throttle、流式结果等场景的状态迁移验证。赞分享前端GraphQL【免费下载链接】apollo Apollo/GraphQL integration for VueJS项目地址https://gitcode.com/gh_mirrors/apollo2/apollo点击查看免费下载相关推荐vue/apollo-composable 的 useQuery 深入指南Vue 3 响应式 GraphQL 查询完全解析vue/apollo composable 的 useQuery 深入指南Vue 3 响应式 GraphQL 查询完全解析 useQuery 是 vue/前端GraphQLmall 项目 Docker 容器化部署实战镜像、容器、私有仓库与 Compose 编排全攻略mall 项目 Docker 容器化部署实战镜像、容器、私有仓库与 Compose 编排全攻略 导读 本文是一份面向 mall 电商项目基于 Spring前端GraphQLCSS3 属性详解一文本阴影、盒模型尺寸、私有前缀与边框特效CSS3 属性详解一文本阴影、盒模型尺寸、私有前缀与边框特效 本文承接 CSS3 选择器详解 https://link.gitcode.com/i/3a7前端GraphQL上一篇KernelSU x86_64 支持详解syscall 表加固的兼容方案与 KSU_X86_PATCH_SYSCALL_DISPATCHER 实战下一篇Ingress-Nginx Controller 的 Kubernetes RBAC 权限模型ServiceAccount、Role 与 ClusterRole 完整解读创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考