ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

Apollo Client 版本演进全解读:从 4.0 架构重构到 4.2 类型安全与事件驱动 Refetch

Apollo Client 版本演进全解读:从 4.0 架构重构到 4.2 类型安全与事件驱动 Refetch Apollo Client 版本演进全解读从 4.0 架构重构到 4.2 类型安全与事件驱动 Refetch【免费下载链接】apollo-clientThe industry-leading GraphQL client for TypeScript, JavaScript, React, Vue, Angular, and more. Apollo Client delivers powerful caching, intuitive APIs, and comprehensive developer tools to accelerate your app development.项目地址: https://gitcode.com/gh_mirrors/ap/apollo-client这篇技术指南以仓库根目录的 CHANGELOG.md覆盖 Apollo Client 2.3.2 至 4.2.12 的全部版本记录为核心脉络系统梳理 Apollo Client 4.x 系列带来的架构级变革框架无关核心、统一错误处理、dataState结果状态、可插拔增量交付、classic/modern 双签名类型系统以及 4.2 全新引入的事件驱动自动 RefetchRefetchEventManager。读完本文你将理解每个版本为什么改、改了什么、如何迁移并能直接对照仓库源码src/core、src/errors、src/incremental、src/local-state等验证底层实现。一、CHANGELOG 覆盖范围与阅读方法当前仓库的 CHANGELOG.md 是一份累计超过 1 万行的完整版本历史覆盖从 2018 年的2.3.2到当前最新的4.2.124.2.x 系列最新的补丁与次要版本当前头部包含类型系统现代化与事件驱动 Refetch 两大主线4.0.0 大版本一次完整的架构重构文内含独立的Release Notes专题章节见 CHANGELOG.md 4.0.0 一节是理解现代 Apollo Client 设计哲学的核心材料3.x / 2.x 系列早期历史记录了大量缓存、ObservableQuery、fetch policy 相关的修复对排查历史问题仍有参考价值。版本条目统一采用 Changesets 格式每个条目包含 PR 链接、提交哈希、贡献者与变更说明并用### Minor Changes新特性与### Patch Changes修复分类。下文聚焦最有价值的 4.x 主线展开。二、Apollo Client 4.0一次彻底的架构重构4.0.0 的 Release Notes 明确将其定位为更现代、更高效、更类型安全的 GraphQL 客户端体验核心围绕开发者体验、包体积优化与框架灵活性三个方向。2.1 框架无关的核心Framework-Agnostic Core4.0 将 React 功能与核心库分离React 相关导出统一收归apollo/client/react核心不再依赖 React。这意味着你可以在任意 JavaScript 框架中使用 Apollo Client 而不会引入 React 依赖。仓库中 src/react/index.ts 与 src/core/ApolloClient.ts 的目录划分正是这一架构的落地体现。2.2 更小的包体积局部状态按需引入client指令能力改为通过LocalState类按需启用源码见 src/local-state/LocalState.ts不使用局部状态时不会被打包现代构建目标转译目标为since 2023, node 20, not dead充分利用现代 JavaScript 特性更优的 Tree-Shakingpackage.json中规范的exports字段让死代码消除更彻底。2.3 统一错误处理Unified Error Handling4.0 移除了ApolloError改用一组更细粒度的错误类并统一收敛到单一的error属性错误类语义CombinedGraphQLErrors服务器返回的 GraphQL 错误源码见 src/errors/CombinedGraphQLErrors.tsServerError非 GraphQL 的服务器错误ServerParseError服务器响应解析错误UnconventionalError非 Error 对象被 throw 时的包装LinkError链路Link抛出的错误通过.is()判定这些类都提供静态.is()方法用于类型收窄网络错误也遵循errorPolicy设置外部错误则原样透传不再包装。迁移示例// Apollo Client 3 if (error instanceof ApolloError) { console.log(error.graphQLErrors); console.log(error.networkError); } // Apollo Client 4 import { CombinedGraphQLErrors } from apollo/client; if (CombinedGraphQLErrors.is(error)) { console.log(error.errors); // GraphQL errors } else if (error) { console.log(error.message); // Other errors }2.4 全新的dataState属性dataState清晰标识查询结果的完整性是 4.0 类型系统的基石之一empty无数据data为undefinedpartialreturnPartialData为true时从缓存读到的部分数据streamingdefer查询仍在流式返回中的不完整数据complete完全满足的查询结果。const { data, dataState } useQuery(MY_QUERY); if (dataState complete) { // TypeScript 知道 data 字段是完整的 console.log(data.allFields); } else if (dataState partial) { // TypeScript 知道 data 可能缺字段 console.log(data?.someField); }2.5 可插拔的增量交付defer/stream4.0 将增量交付设计为可配置、面向未来的机制通过incrementalHandler注入。仓库中的导出见 src/incremental/index.tsimport { Defer20220824Handler } from apollo/client/incremental; const client new ApolloClient({ // ... incrementalHandler: new Defer20220824Handler(), });NotImplementedHandler默认处理器一旦使用defer直接抛出异常Defer20220824Handler支持 Apollo Router 的增量格式同时以GraphQL17Alpha2Handler别名导出。2.6 局部状态管理LocalState 类client字段解析改为显式启用import { LocalState } from apollo/client/local-state; const client new ApolloClient({ cache, localState: new LocalState({ resolvers: { Query: { myField: () Hello World, }, }, }), });同时 resolver 的context结构发生变化4.0 中context提供client、requestContext、phase三个字段cache改为通过client.cache获取// Apollo Client 4 const resolver (parent, args, context, info) { const { client, requestContext, phase } context; const cache client.cache; };2.7 React 侧改进useLazyQuery重构不再接受variables/context选项改由execute接收execute只接受variables与context禁止在渲染期间或 SSR 中调用新查询启动时自动取消在途查询useMutation移除ignoreResults选项如需 fire-and-forget 直接使用client.mutateuseQuerynotifyOnNetworkStatusChange默认改为true移除废弃的onCompleted/onError回调新 SSR APIprerenderStatic取代旧的 SSR 函数支持 React 19 的 prerender APIimport { prerenderStatic } from apollo/client/react/ssr; const html await prerenderStatic(App /, { client, });React Compiler 支持提供apollo/client/react/compiled入口见 src/react/index.ts 中 compiled 运行时内置 React 17 兼容的运行时 polyfill。2.8 Link 体系演进全部类化创建函数creator function统一迁移为类// Apollo Client 3 import { createHttpLink, setContext } from apollo/client; const httpLink createHttpLink({ uri: /graphql }); const authLink setContext((operation, prevContext) { /*...*/ }); // Apollo Client 4 import { HttpLink, SetContextLink } from apollo/client; const httpLink new HttpLink({ uri: /graphql }); const authLink new SetContextLink((prevContext, operation) { /*...*/ });ErrorLink也同步改为单一error属性与错误类.is()判定对应仓库 src/link/error/index.ts。2.9 迁移工具与破坏性变更清单4.0 提供自动化 codemod# 基础用法 npx apollo/client-codemod-migrate-3-to-4 src # TypeScript 项目分开执行 npx apollo/client-codemod-migrate-3-to-4 --parser ts --extensions ts src npx apollo/client-codemod-migrate-3-to-4 --parser tsx --extensions tsx srccodemod 依次处理导入更新React 导入迁往apollo/client/react→ 类型迁移迁往新的命名空间位置→ Link 更新创建函数转类→ 被移除导出的处理迁往apollo/client/v4-migration。关键的破坏性变更对应仓库 src/core/ApolloClient.ts 的构造函数包括安装rxjs成为 peer dependency安装命令为npm install apollo/client graphql rxjs构造函数link变为必填不再隐式创建HttpLinkuri/headers/credentials移除改用HttpLinkname/version移入clientAwarenessresolvers移入LocalState构造器connectToDevTools换成devtools.enableddisableNetworkFetches更名为prioritizeCacheValues类型系统移除TContext、TCacheShape泛型类型迁入命名空间自定义 context 改走模块增强Observable从zen-observable迁移到 RxJS转换必须调用.pipe()使用 RxJS 操作符测试MockedProvider默认带真实延迟20–50ms移除createMockClient改用MockLink性能与构建不再为现代特性降级转译、不内置 polyfill、开发模式通过 export conditions 控制、完善的exports字段与 source maps移除的导出React render-prop 组件apollo/client/react/components、HOCapollo/client/react/hoc、apollo/client/react/parser、apollo/client/utilities/globals。官方建议的升级路径先升到 3.14 收集废弃警告 → 安装rxjs→ 运行 codemod → 更新ApolloClient初始化显式HttpLink、按需LocalState→ 重写错误处理 → 重点回归 SSR、错误处理与局部状态。三、Apollo Client 4.1增量交付与 Fragment 观察能力增强4.1.0 在 4.0 基础上继续强化增量交付与缓存观察 APIGraphQL17Alpha9Handler支持graphql17.0.0-alpha.9实现的更新版defer增量格式源码见 src/incremental/handlers/graphql17Alpha9.ts。注意只有服务器实现了新版格式时才应使用它Apollo Router 用户应继续使用Defer20220824Handlerimport { GraphQL17Alpha9Handler } from apollo/client/incremental; const client new ApolloClient({ incrementalHandler: new GraphQL17Alpha9Handler(), });该处理器会把accept头更新为multipart/mixed;incrementalSpecv0.2以请求最新格式。stream支持Defer20220824Handler与GraphQL17Alpha2Handler均可处理stream指令默认只在最后一个 chunk 时截断stream数组且仅当结果携带 stream 信息时才使用默认流式 merge 函数。Fragment 观察增强useFragment/useSuspenseFragment/client.watchFragmentfrom支持数组一次观察多个实体data按索引对应from数组from: null时结果固定为{ data: null, dataState: complete, complete: true }返回的 Observable 新增getCurrentResult()方法相同 fragment、变量与标识符的 watch 会去重并尽量复用已有 Observable 以提升性能。缓存写入增强cache.write/cache.writeQuery/client.writeQuery新增extensions选项使 GraphQL 操作的extensions在 merge 函数中可用源码参见 src/cache 相关实现InMemoryCache不再过滤read函数显式返回的undefined数组项readFragment/watchFragment/updateFragment全面支持from选项。client字段行为修正定义了read函数时不再把回退值强制设为null而是以existing undefined调用readLocalState在无 resolver 且缓存无法解析client字段resolvesClientField返回false时才警告并设null。四、Apollo Client 4.2双签名类型系统与事件驱动 Refetch4.2.0 是本仓库当前版本主线中最具革新意义的一次次要版本包含两个重量级特性。4.14.2 classic 与 modern 双签名Signature Styles4.2 为方法与 hooks 引入两种签名风格Classic signatures默认与 4.2 之前完全一致保持向后兼容支持手写 TypeScript 泛型如useSuspenseQueryMyData(...)。但官方明确建议改用TypedDocumentNode让类型自动推断Modern signatures自动把声明的defaultOptions纳入返回类型类型更准确从文档节点推断类型不支持手动传泛型参数传入会产生类型错误。方法/钩子会在DeclareDefaultOptions中声明了任意非可选属性时全局自动切换到 modern 签名// apollo.d.ts import apollo/client; declare module apollo/client { namespace ApolloClient { namespace DeclareDefaultOptions { interface WatchQuery { errorPolicy: all; // 非可选 → 自动激活 modern 签名 } } } }也可以不声明defaultOptions、直接手动切换到 modern 签名或声明后手动切回 classic 用于迁移不推荐长期使用因为会导致类型与运行时不一致// apollo.d.ts import apollo/client; declare module apollo/client { export interface TypeOverrides { signatureStyle: modern; // 或 classic } }4.2 defaultOptions 类型安全必须全局登记从 4.2 开始某些defaultOptions类型必须全局登记否则ApolloClient构造会直接报 TypeScript 错误。可登记的键包括WatchQuery的errorPolicy与returnPartialData、Query与Mutate的errorPolicy。// apollo.d.ts import apollo/client; declare module apollo/client { namespace ApolloClient { namespace DeclareDefaultOptions { interface WatchQuery { errorPolicy: all; } interface Query { errorPolicy: all; } interface Mutate { errorPolicy: all; } } } }登记后useSuspenseQuery(MY_QUERY)的data类型会从TData自动变为TData | undefined与发生错误时data可能为undefined的运行时行为保持一致单次调用显式传errorPolicy: none又会把data收窄回TData。若同一应用存在多个defaultOptions冲突的客户端实例可用联合类型放宽约束declare module apollo/client { export namespace ApolloClient { export namespace DeclareDefaultOptions { interface WatchQuery { errorPolicy?: none | all | ignore; returnPartialData?: boolean; } } } }代价是返回类型会变得更泛化把属性设为可选errorPolicy?:等价于在联合类型中加入 TypeScript 默认值none。仅使用部分取值时建议声明精确的必选联合如errorPolicy: all | ignore以保持签名收窄。4.3 类型安全扩展到 mutate 与 preloadQueryclient.mutate/useMutationerrorPolicy现在流入结果类型对应仓库 src/core/types.ts 中ApolloClient.MutateResultnone→{ data: TData; error?: never }all→{ data: TData | undefined; error?: ErrorLike }ignore→{ data: TData | undefined; error?: never }。声明DeclareDefaultOptions.Mutate.errorPolicy后hooks 与方法返回类型随之收窄单次调用显式传errorPolicy可覆盖默认值。preloadQuery来自createQueryPreloaderDeclareDefaultOptions.WatchQuery的默认值会正确作用于PreloadedQueryRef的 data states例如声明errorPolicy: all后preloadQuery(QUERY)返回PreloadedQueryRefTData, TVariables, complete | streaming | empty。4.4 事件驱动自动 RefetchRefetchEventManager4.2 通过RefetchEventManager类实现基于事件的自动 refetch如窗口聚焦window focus与网络重连。核心实现见 src/core/RefetchEventManager.ts内置事件源为 src/core/refetchSources/windowFocusSource.ts 与 src/core/refetchSources/onlineSource.ts。事件 refetch 完全按需启用构造RefetchEventManager并传入ApolloClient构造函数即可激活事件监听import { ApolloClient, InMemoryCache, RefetchEventManager, windowFocusSource, onlineSource, } from apollo/client; const client new ApolloClient({ link, cache: new InMemoryCache(), refetchEventManager: new RefetchEventManager({ sources: { // 窗口聚焦时 refetch windowFocus: windowFocusSource, // 用户恢复在线时 refetch online: onlineSource, }, }), });默认情况下所有活跃查询都会在事件触发时 refetch查询可逐事件关闭或整体关闭// 窗口聚焦时不 refetch但保留 online useQuery(QUERY, { refetchOn: { windowFocus: false }, }); // 关闭该查询的所有事件驱动 refetch useQuery(OTHER_QUERY, { refetchOn: false, }); // 无条件启用所有事件 useQuery(LIVE_DASHBOARD, { refetchOn: true, }); // 事件触发时动态决定是否 refetch useQuery(LIVE_DASHBOARD, { refetchOn: ({ source, payload }) { if (source windowFocus) { return someCondition(payload); } return true; }, });也可以按事件配置动态回调useQuery(LIVE_DASHBOARD, { refetchOn: { windowFocus: ({ payload }) someCondition(payload), }, });per-query 按需启用模式在defaultOptions.watchQuery.refetchOn设为false或true、回调函数再逐查询开启。当defaultOptions与 per-query 的refetchOn同时提供时两者会合并——defaultOptions的值作用于 per-query 对象未显式配置的事件const client new ApolloClient({ link, cache, refetchEventManager: new RefetchEventManager({ sources: { windowFocus: windowFocusSource }, }), defaultOptions: { watchQuery: { refetchOn: false }, }, }); // 只有该查询会在窗口聚焦时 refetch useQuery(DASHBOARD_QUERY, { refetchOn: { windowFocus: true } });自定义事件通过 TypeScript 模块增强注册事件名与 payload 类型再提供返回 Observable 的 source 函数发出值即事件 payloadimport { Observable } from apollo/client; import { filter } from rxjs; import { AppState, AppStateStatus, Platform } from react-native; declare module apollo/client { interface RefetchEvents { reactNativeAppStatus: AppStateStatus; } } const refetchEventManager new RefetchEventManager({ sources: { reactNativeAppStatus: () { return new Observable((observer) { const subscription AppState.addEventListener(change, (status) { observer.next(status); }); return () subscription.remove(); }).pipe( filter((status) Platform.OS ! web status active) ); }, }, });手动触发调用emit(eventName, payload)即可命令式触发事件 refetchrefetchEventManager.emit(reactNativeAppStatus, active);无源事件Sourceless events某个事件没有自动检测逻辑、只支持命令式emit时source 可声明为true并将事件类型声明为void以省略 payload 参数declare module apollo/client { interface RefetchEvents { userTriggered: void; } } const refetchEventManager new RefetchEventManager({ sources: { userTriggered: true }, }); refetchEventManager.emit(userTriggered);注意对未注册 source 的事件调用emit会输出警告并成为 no-op。自定义 handler事件触发时默认 handler 调用client.refetchQueries({ include: active })再按各查询的refetchOn设置过滤。可针对某事件覆盖 handler例如把所有查询含standby都纳入 refetchconst refetchEventManager new RefetchEventManager({ // ... handlers: { userTriggered: ({ client, source, payload, matchesRefetchOn }) { return client.refetchQueries({ include: all, onQueryUpdated: (observableQuery) { return matchesRefetchOn(observableQuery); }, }); }, }, });handler 必须返回RefetchQueriesResult或void返回void表示该事件跳过 refetch。此外 4.2.0 还支持通过构造选项defaultHandler或实例方法setDefaultEventHandler覆盖默认handler未配置 per-source handler 时兜底运行见 src/core/RefetchEventManager.ts 中Options.defaultHandler的注释说明。4.5 4.2.x 补丁版本要点4.2.12修复多字节 UTF-8 字符被 multipart 响应块切分后丢失的问题PR #134004.2.11新增开发模式警告——网络结果写入缓存后回读得到部分结果时提示通常指向merge/read函数未修复缓存缺失字段4.2.10修复optimisticResponse导致client.mutate返回类型意外放宽、常量类型变量导致returnPartialData/errorPolicy类型被放宽、modern 签名下未知选项未被 TypeScript 拦截等问题refetch/fetchMore/useLazyQuery的execute返回类型随errorPolicy收窄4.2.9修复变量显式传undefined时默认值未在缓存读取中生效、export查询对导出变量键控字段的缓存更新无响应的问题4.2.8connectToDevtools的setTimeout不再在非 Chrome/Firefox 环境触发消除测试抖动4.2.6缓存写入提速——仅在结果携带 stream 信息时才做stream检测避免对每个写入字段做完整 ASTvisit嵌套字段上的stream不再被视为流式字段本身4.2.5从公共入口导出KeyArgsFunction与RelayFieldPolicy类型4.2.4修复client.readFragment/client.readQuery忽略 options 对象中optimistic选项的问题4.2.3graphqlv17 被接纳为合法 peer dependency仓库 patches 目录中亦包含graphql-17-alpha9的补丁佐证4.2.2refetch 时若掩码masked数据与上一结果深度相等则保持引用相等4.2.1修复useLazyQuery在渲染间隔中修改pollInterval不生效的问题。五、3.x 至 2.x历史演进一瞥4.0 之前的历史版本同样记录了大量关键演进阅读时可按需回溯3.14作为 4.0 前的过渡版本集中输出废弃警告是官方升级路径的第 1 步3.8引入useFragment、useSuspenseFragment、useBackgroundQuery等 hooks 与新 SSR 能力3.6–3.7缓存、fetchMore、网络状态与 Link 链路的持续修复3.0InMemoryCache归一化缓存与字段策略field policies成为主流2.x记录了ObservableQueryTData, TVariables泛型化、QueryOptions与WatchQueryOptions分离、fetch policy 与 SSR 修复等历史沿革。六、结语如何利用这份 CHANGELOG 指导开发升级前先读 4.0.0 Release Notes 的 Breaking Changes 清单走完3.14 → 装 rxjs → codemod → 改初始化 → 改错误处理 → 回归测试的标准路径接入 4.2 新特性事件驱动 Refetch 从 src/core/RefetchEventManager.ts 与 src/core/refetchSources 出发即可快速上手类型安全能力则对照 src/core/types.ts 与DeclareDefaultOptions的模块增强模式排查存量问题按版本号在 CHANGELOG.md 中检索对应修复项通常能快速定位到源码与测试如 src/core/tests做到改了什么、为什么改有据可查。从 4.0 的架构重构到 4.2 的类型系统现代化与事件驱动 refetchApollo Client 的演进主线始终围绕更小的包、更准的类型、更灵活的框架适配展开——这份 CHANGELOG 既是升级手册也是理解客户端缓存与状态管理的绝佳源码级教材。【免费下载链接】apollo-clientThe industry-leading GraphQL client for TypeScript, JavaScript, React, Vue, Angular, and more. Apollo Client delivers powerful caching, intuitive APIs, and comprehensive developer tools to accelerate your app development.项目地址: https://gitcode.com/gh_mirrors/ap/apollo-client创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表