Relay 的 GraphQLSubscriptionConfig 类型详解:从字段语义到 requestSubscription/useSubscription 落地实践
发布时间:2026/9/23 1:33:01 锦皓数字建站

前端开发工具【免费下载链接】relayRelay is a JavaScript framework for building>项目地址https://gitcode.com/gh_mirrors/relay29/relay点击查看免费下载本文基于 Relay 17.0.0 官方 API 参考文档website/versioned_docs/version-v17.0.0/api-reference/types/GraphQLSubscriptionConfig.md展开系统讲解GraphQLSubscriptionConfig类型的每一个字段及其语义并结合 requestSubscription.js 与 useSubscription.js 的源码实现说明这些字段在 Relay Runtime 中如何被消费。读完本文你将掌握在 React 应用中正确声明、发起并清理 GraphQL 订阅的完整配置方法包括回调时序、Store 更新策略与类型化订阅的最佳实践。一、GraphQLSubscriptionConfig是什么GraphQL Subscription 是客户端订阅服务端事件流的一种机制服务端事件发生时客户端收到通知并执行一次查询从而让界面实时刷新。在 Relay 中订阅操作由一个配置对象驱动这个对象就是GraphQLSubscriptionConfigTSubscriptionPayload。根据 API 参考文档的定义它是一个对象类型Object承载订阅所用的 GraphQL 节点、变量、网络缓存选项以及各类回调与 Store 更新函数字段必填类型作用cacheConfig可选CacheConfig订阅请求的网络/缓存行为配置subscription必填GraphQLTaggedNode用graphql模板字面量声明的订阅节点variables必填变量对象传给订阅的变量onCompleted可选() void订阅建立完成后执行的回调onError可选(Error) void出错时执行的回调onNext可选(TSubscriptionPayload) void收到新数据时执行的回调updater可选SelectorStoreUpdater收到 payload 后对 Relay Store 进行命令式更新注在 TypeScript 声明requestSubscription.d.ts中该类型还额外包含可选的configs字段DeclarativeMutationConfig[]用于声明式地操作连接connection例如RANGE_ADD追加新边。API 文档面向纯类型字段展开configs属于声明式指令的补充能力后文会结合源码说明。二、核心字段逐个拆解2.1subscription订阅的 GraphQL 节点subscription必须是GraphQLTaggedNode即通过graphql模板字面量声明的订阅。与 query 非常相似唯一区别是使用subscription关键字例如subscription FeedbackLikeSubscription($input: FeedbackLikeSubscribeData!) { feedback_like_subscribe(data: $input) { feedback { like_count } } }在 JS 中对应import {graphql} from react-relay; const feedbackLikeSubscription graphql subscription FeedbackLikeSubscription($input: FeedbackLikeSubscribeData!) { feedback_like_subscribe(data: $input) { feedback { like_count } } } ;这里feedback_like_subscribe是订阅根字段subscription root field它在后端建立订阅流。Relay 编译器会为订阅生成对应的*.graphql.js类型文件例如测试仓库中的 requestSubscriptionTestCommentCreateSubscription.graphql.js其中导出了$variables、$data等类型供静态类型检查使用。运行时强校验requestSubscription的实现会先调用getRequest(config.subscription)取出请求并校验操作类型——如果传入的不是subscription操作会直接抛出requestSubscription: Must Use Subscription operation错误见 requestSubscription.js。2.2variables订阅变量variables是必填字段传递给订阅查询。它同样支持 GraphQL 变量与 query/fragment 的用法一致requestSubscription(environment, { subscription, variables: {input: {feedbackId: 4}}, });当使用 Flow/TypeScript 的泛型参数时variables会被静态约束为订阅节点导出的$variables类型。2.3onNext收到新数据时执行onNext在每次收到订阅 payload 时触发回调参数类型为TSubscriptionPayload。关键语义来自源码onNext收到的不是网络层的原始响应而是 Relay 从 Store 中按订阅的 fragment 读取出来的数据。在 requestSubscription.js 中可以看到onNext会从响应中提取extensions.__relay_subscription_root_id若响应为数组则取第一个元素用该 ID 构造新的 Reader Selector然后调用environment.lookup(selector).data读取 Store 数据将读取到的数据传给onNext。也就是说onNext拿到的数据是「读到 fragment spread 边界为止」的已规范化数据与订阅声明中选中的字段一一对应。2.4onError出错时执行onError在订阅出错时触发回调接收Error对象。它对应RelayObservable订阅器中的error回调例如网络层断开、服务端返回错误等场景。2.5onCompleted订阅结束时执行onCompleted在订阅建立完成complete后执行即服务端结束订阅流时触发回调无参数。它在 requestSubscription.js 中被直接映射为 Observable 的complete回调。2.6cacheConfig网络缓存行为cacheConfig复用CacheConfig类型字段如下字段类型语义forceboolean为true时无条件发起请求忽略任何已配置的响应缓存pollnumber按指定毫秒间隔轮询实现实时更新该值会传给setTimeoutliveConfigIdstring通过调用 GraphQLLiveQuery 实现实时更新表示 live query 时的网关配置metadataobject用户提供的元数据transactionIdstring用户提供的值用作某次操作执行实例的唯一 ID这些字段与 TypeScript 声明 RelayRuntimeTypes.d.ts 完全一致。在运行时cacheConfig会被透传给网络层executeSubscription在 RelayModernEnvironment.js 中执行this.getNetwork().execute(operation.request.node.params, operation.request.variables, operation.request.cacheConfig || {}, null)即把cacheConfig作为第三个参数传给自定义的 Network 执行函数。2.7updater命令式更新 Storeupdater是可选的SelectorStoreUpdater签名如下(store: RecordSourceSelectorProxy, data) void它让你能够命令式地读写 Relay Store可以创建全新记录、更新已有记录或删除记录完全掌控订阅 payload 如何写入 Store。Relay Store 读写的完整 API 参见 Store API 参考。一个典型场景订阅返回的新评论需要被追加进某个 connection此时除了声明式configs也可以用updater手动操作requestSubscription(environment, { subscription, variables, updater: (store, data) { const rootField store.getRootField(commentCreateSubscribe); // 读取返回的 edge手动写入连接 }, });注意约束源码中requestSubscription会发出警告——updater与configs只能二选一同时提供会触发requestSubscription: Expected only one ofupdaterandconfigsto be provided的 warning见 requestSubscription.js。若提供了configs内部会通过RelayDeclarativeMutationConfig.convert把声明式配置转换为实际的 updater 再执行。三、两个承载类型CacheConfig与SelectorStoreUpdater原文档通过模块引用的方式将两个承载类型嵌入GraphQLSubscriptionConfig页面CacheConfig完整定义见 CacheConfig.md上文 2.6 节已详述各字段。SelectorStoreUpdater完整定义见 SelectorStoreUpdater.md。它是一个(store, data) void函数store类型为RecordSourceSelectorProxy。需要特别说明的是updater的执行时机订阅 payload 到达后Relay 先把它规范化写入 Store然后才执行updater这一点与 mutation 的optimisticUpdater/updater时序一致。因此 updater 中读取的数据已经包含了本次 payload 写入的内容。四、两大入口requestSubscription与useSubscription4.1 命令式 APIrequestSubscriptionrequestSubscription(environment, config)是建立订阅的命令式 API返回一个Disposable调用dispose()即取消订阅。最小可用示例import {graphql, requestSubscription} from react-relay; import type {Environment} from react-relay; const subscription graphql subscription UserDataSubscription($input: InputData!) { user_data_subscribe(input: $input) { user { id name } } } ; function createSubscription(environment: Environment): Disposable { return requestSubscription(environment, { subscription, variables: {input: {userId: 4}}, onNext: response { // 每次服务端事件后从 Store 读取到的数据 }, onError: error { console.error(error); }, onCompleted: () { // 订阅被服务端关闭 }, }); } // 需要取消时 const disposable createSubscription(environment); // ... disposable.dispose();对应 API 参考见 request-subscription.mdx。运行链路以 requestSubscription.js 为据getRequest(config.subscription)获取请求节点校验 operation 类型createOperationDescriptor(subscription, variables, cacheConfig)创建操作描述符若同时传入updater与configs则发出警告有configs时用RelayDeclarativeMutationConfig.convert转换调用environment.executeSubscription({operation, updater})见 RelayModernEnvironment.js对返回的RelayObservable调用.subscribe({complete, error, next})返回{dispose: sub.unsubscribe}。值得强调的是Observable 的惰性executeSubscription只有在被订阅.subscribe(...)后才会真正发起网络请求——这正是requestSubscription最后一步显式 subscribe 的原因。4.2 声明式 HookuseSubscription在 React 组件中更常用的是useSubscription(config)。它只是requestSubscription的薄封装见 useSubscription.js组件挂载时用给定 config 建立订阅组件卸载时自动取消订阅当environment、config或requestSubscriptionFn变化时先取消旧订阅再以新值重新订阅。import {graphql, useSubscription} from react-relay; import {useMemo} from react; const subscription graphql subscription UserDataSubscription($input: InputData!) { user_data_subscribe(input: $input) { user { id name } } } ; function UserComponent({id}) { // 重要config 必须被 memoize // 否则 useSubscription 会在每次渲染时重新订阅 const config useMemo( () ({ variables: {input: {userId: id}}, subscription, onNext: response console.log(response), }), [id], ); useSubscription(config); return null; }⚠️ 核心实践警告GraphQLSubscriptionConfig对象传给useSubscription前必须使用useMemo缓存依赖项为变量与 subscription 节点。若每次渲染都新建对象会导致useEffect依赖变化、订阅被反复 dispose 并重建。源码注释也明确提示了这一要求见 useSubscription.js。对应 API 参考见 use-subscription.mdx。五、类型化订阅为 config 提供泛型参数与 query 一样Relay 编译器会为订阅生成类型文件。以测试用例 requestSubscriptionTestCommentCreateSubscription.graphql.js 为例其中导出export type requestSubscriptionTestCommentCreateSubscription$variables { readonly input: {...}, }; export type requestSubscriptionTestCommentCreateSubscription$data { readonly commentCreateSubscribe: {...} | null, };在 Flow 中useSubscription/requestSubscription接受类型参数使得整个GraphQLSubscriptionConfig静态类型化import type {FeedbackLikeSubscription} from FeedbackLikeSubscription.graphql; const config: GraphQLSubscriptionConfigFeedbackLikeSubscription { subscription, variables: {...}, };官方指南 graphql-subscriptions.mdx 明确建议始终提供该类型参数是最佳实践因为它能让variables、onNext的 payload 类型等得到编译期校验。注意onNext回调参数类型为TSubscriptionPayload即订阅响应的$data类型。六、订阅数据的写入与组件刷新当订阅 payload 到达时Relay 会把它规范化并提交到 Store_execute内部经由OperationExecutor.execute与 publish queue见 RelayModernEnvironment.js。随后Relay 在 Store 中找到 id 匹配的记录并更新字段值所有依赖这些字段的组件自动重渲染。因此更好的做法是在订阅里 spread fragment而不是手动挑选字段这样订阅事件会刷新所有相关组件并保持数据一致subscription FeedbackLikeSubscription($input: FeedbackLikeSubscribeData!) { feedback_like_subscribe(data: $input) { feedback { ...FeedbackDisplay_feedback ...FeedbackDetail_feedback } } }此外订阅同样支持声明式指令例如deleteRecord删除记录与 connection 相关的声明式指令RANGE_ADD等前者示例subscription DeletePostSubscription($input: DeletePostSubscribeData!) { delete_post_subscribe(data: $input) { deleted_post { id deleteRecord } } }这些指令能力由configs字段承载具体可参考 graphql-subscriptions.mdx。七、网络层配置让订阅真正跑起来GraphQLSubscriptionConfig只是客户端配置要让订阅真正工作网络层必须支持 subscription。Relay 的Network.create(fetchQuery, subscribe)接受第二个参数subscribe它把操作信息operationName、query、variables转成 Observable 流。官方指南给出了基于graphql-wsWebSocket 协议的实现import {Network, Observable} from relay-runtime; import {createClient} from graphql-ws; const wsClient createClient({url: ws://localhost:3000}); const subscribe (operation, variables) { return Observable.create(sink { return wsClient.subscribe( { operationName: operation.name, query: operation.text, variables, }, sink, ); }); }; const network Network.create(fetchQuery, subscribe);requestSubscription内部正是通过getNetwork().execute(...)走到这个subscribe函数见 RelayModernEnvironment.jscacheConfig、variables等字段也在这里被透传给网络层。完整网络层指南见 network-layer 指南。八、测试验证仓库中的真实用例仓库的运行时测试 requestSubscription-test.js 覆盖了GraphQLSubscriptionConfig各字段的真实行为使用graphql标签声明订阅节点、传入variables与声明式configsRANGE_ADD追加评论 edge见 requestSubscription-test.js通过environment.mock.nextValue(CommentCreateSubscription, subscriptionPayload)模拟服务端事件验证 Store 中 connection 被正确追加见同文件 L141-L159测试所用的订阅根字段commentCreateSubscribe、feedbackLikeSubscribe、configCreateSubscribe定义在测试 Schema testschema.graphql 的type Subscription中。这些用例是理解subscription、variables、configs/updater字段如何协同工作的最佳入口。九、常见误区与最佳实践小结务必 memoize config传给useSubscription的GraphQLSubscriptionConfig必须useMemo否则每次渲染都会重建订阅。onNext拿到的是 Store 数据它不是原始网络响应而是按 fragment 从 Store 读取的规范化数据需要原始 payload 时应自行在网络层处理。updater与configs二选一同时提供会触发 warning声明式 connection 操作优先用configs复杂逻辑用updater。订阅节点必须是subscription操作否则requestSubscription直接抛错。提供类型参数始终为GraphQLSubscriptionConfig提供订阅节点导出的类型让variables与 payload 得到静态校验。网络层需显式支持Network.create(fetchQuery, subscribe)的第二个参数是订阅能够建立的前提。cacheConfig会透传网络层force、poll、liveConfigId、metadata、transactionId可按需用于控制缓存与实时策略。十、延伸阅读类型定义原文GraphQLSubscriptionConfig.md、CacheConfig.md、SelectorStoreUpdater.mdAPI 参考requestSubscription、useSubscription、Store API实战指南GraphQL Subscriptions 指南源码实现requestSubscription.js、useSubscription.js、RelayModernEnvironment.js、RelayRuntimeTypes.d.ts测试用例requestSubscription-test.js、testschema.graphql赞分享前端开发工具【免费下载链接】relayRelay is a JavaScript framework for building>项目地址https://gitcode.com/gh_mirrors/relay29/relay点击查看免费下载相关推荐Relay 中 GraphQLSubscriptionConfig 类型详解从字段语义到订阅生命周期与 store 更新Relay 中 GraphQLSubscriptionConfig 类型详解从字段语义到订阅生命周期与 store 更新 GraphQLSubscriptio前端开发工具Relay 14 GraphQLSubscriptionConfig 完整指南用 requestSubscription 与 useSubscription 构建实时数据流Relay 14 GraphQLSubscriptionConfig 完整指南用 requestSubscription 与 useSubscription前端开发工具Relay MutationConfig 类型详解字段语义、回调时序与 commitMutation 实战Relay MutationConfig 类型详解字段语义、回调时序与 commitMutation 实战 MutationConfig 是 Relay 中通前端开发工具创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
锦
锦皓数字建站
深耕本土企业品牌数字化升级,专注原创端正雅致商务官网,从视觉设计到稳定运维全程保驾护航。