
前端开发工具【免费下载链接】relayRelay is a JavaScript framework for building>项目地址https://gitcode.com/gh_mirrors/relay29/relay点击查看免费下载requestSubscription是 Relaypackages/react-relay提供的命令式imperative订阅 API用于在任意时机例如事件回调、服务端推送触发时建立 GraphQL Subscription并在收到服务端事件流数据后自动将其规范化并写入 Relay Store驱动依赖数据的组件实时刷新。阅读本文后你将掌握requestSubscription(environment, config)的完整签名、GraphQLSubscriptionConfig中每一个配置字段的含义与底层实现、Disposable返回值的使用方式以及如何借助updater、声明式指令declarative directives和网络层 WebSocket 配置将其落地到真实应用。本文以 version-v17.0.0 的 requestSubscription 参考文档 为主体骨架结合relay-runtime与react-relay的源码实现与单元测试展开讲解。requestSubscription是什么requestSubscription是一个命令式 API用于建立 GraphQL Subscription。它与 React Hooks 中声明式的useSubscription形成互补Hook 适合在组件挂载时自动建立订阅而requestSubscription可以在任何 JavaScript 环境中调用——包括事件处理器、定时任务、非组件模块等场景。import {graphql, requestSubscription} from react-relay; const subscription graphql subscription UserDataSubscription($input: InputData!) { # ... } ; function createSubscription(environment: IEnvironment): Disposable { return requestSubscription(environment, { subscription, variables: {input: {userId: 4}}, }); }从源码看requestSubscription.jsrequestSubscription内部的核心调用链为通过getRequest(config.subscription)解析graphql标签生成的请求描述校验operationKind必须是subscription否则直接抛错requestSubscription: Must use Subscription operation使用createOperationDescriptor(subscription, variables, cacheConfig)构造操作描述符调用environment.executeSubscription({operation, updater})获得一个RelayObservable对该 Observable.subscribe({complete, error, next})把回调映射为onCompleted/onError/onNext返回一个封装了sub.unsubscribe的Disposable。参数ArgumentsrequestSubscription接受两个参数environment一个 Relay Environment实现 RelayStoreTypes 中的 IEnvironment。通常来自useRelayEnvironment()或者应用顶层创建的RelayModernEnvironment实例。config类型为GraphQLSubscriptionConfigTSubscriptionPayload的配置对象其字段详见下文。GraphQLSubscriptionConfig配置字段详解以下字段定义源自 GraphQLSubscriptionConfig.md同时与 requestSubscription.d.ts 中的 TypeScript 类型一一对应字段类型必填说明subscriptionGraphQLTaggedNode是使用graphql模板字符串声明的订阅操作variablesVariables是传递给订阅操作的变量cacheConfigCacheConfig否缓存与传输配置见下文onCompleted() void否服务端结束订阅complete时执行的回调onError(error: Error) void否订阅出错时执行的回调onNext(payload: TSubscriptionPayload) void否收到新数据时执行的回调updaterSelectorStoreUpdater否命令式读写 Relay Store 的更新函数configsArrayDeclarativeMutationConfig否声明式变更配置与updater互斥subscription使用graphql标签声明订阅与查询query和变更mutation一样订阅也通过graphql标签声明区别在于顶层关键字是subscription。Relay 编译器会为订阅操作生成对应的类型因此GraphQLSubscriptionConfig可以携带泛型参数实现静态类型检查——这是官方推荐的最佳实践。一个订阅示例源自 graphql-subscriptions.mdxsubscription FeedbackLikeSubscription($input: FeedbackLikeSubscribeData!) { feedback_like_subscribe(data: $input) { feedback { like_count } } }feedback_like_subscribe是订阅根字段subscription root field它在后端建立事件流订阅建立后每当该事件流产生事件客户端就会收到一个形如下面的 payloadRelay 会将其规范化并合并进 Store{ feedback_like_subscribe: { feedback: { id: feedback-id, like_count: 321 } } }由于Feedback类型包含id字段Relay 编译器会自动为订阅补上id的选择收到响应后Relay 会在 Store 中按id匹配对应记录并更新字段值凡是依赖这些字段的组件都会自动重渲染。variables订阅变量与查询/片段一样订阅可以引用 GraphQL 变量variables字段用于传入这些变量的具体值。示例中{input: {userId: 4}}即传入订阅所需的输入参数。cacheConfig缓存与传输配置cacheConfig的类型为CacheConfig其可选字段定义于 CacheConfig.md字段类型说明forceboolean为true时无条件发起请求忽略任何配置的响应缓存状态pollnumber以指定毫秒间隔轮询实现实时更新该值会被传给setTimeoutliveConfigIdstring通过调用 GraphQLLiveQuery 实现实时更新表示做 live query 时网关的一种配置metadataobject用户自定义元数据transactionIdstring用户提供、用于唯一标识某次操作执行实例的值在 requestSubscription.js 中cacheConfig会被透传给createOperationDescriptor最终由environment.executeSubscription传递给网络层执行函数见 RelayModernEnvironment.js 中this.getNetwork().execute(operation.request.node.params, operation.request.variables, operation.request.cacheConfig || {}, null)。因此metadata等字段可以原样到达你的网络层 fetch/subscribe 函数用于埋点、追踪等场景——这一点也被测试用例requestSubscription() cacheConfig所验证requestSubscription-test.js。onCompleted/onError/onNext订阅生命周期回调这三个回调分别对应订阅的三个生命周期事件onNext收到订阅 payload 时执行参数是订阅响应数据在片段展开边界处停止源码中会先通过environment.lookup(selector).data从 Store 读取数据再传给回调requestSubscription.js。onError订阅出错时执行参数为错误对象。onCompleted服务端结束订阅流关闭时执行。updater命令式更新 Relay Storeupdater的类型为SelectorStoreUpdater签名是(store: RecordSourceSelectorProxy, data) void。通过它你可以命令式地直接读写 Relay Store从而对订阅 payload 的落库方式拥有完全控制权可以创建全新的记录record也可以更新或删除已有记录。完整的 Store 读写 API 可参见 store 参考文档。从源码看当configs与updater同时提供时requestSubscription会输出一条 warningrequestSubscription: Expected only one of updater and configs to be providedrequestSubscription.js即两者互斥只能二选一。configs声明式变更配置configs允许你使用DeclarativeMutationConfig以声明方式描述 Store 变更最常见的场景是把新到达的数据追加到某个 connection。源码中若提供了configs会通过RelayDeclarativeMutationConfig.convert(configs, subscription, null /* optimisticUpdater */, config.updater)将其转换为updaterrequestSubscription.js。测试用例Config: RANGE_ADDrequestSubscription-test.js演示了完整用法用RANGE_ADD配置把新评论追加到FeedbackCommentQuery_comments连接上const configs [ { type: RANGE_ADD, connectionName: comments, connectionInfo: [ { key: FeedbackCommentQuery_comments, rangeBehavior: append, }, ], parentID: feedbackId, edgeName: feedbackCommentEdge, }, ]; requestSubscription(environment, { configs, subscription: CommentCreateSubscription, variables: { input: {feedbackId, text: secondCommentBody}, }, });测试随后通过environment.mock.nextValue(CommentCreateSubscription, subscriptionPayload)模拟服务端推送并断言 Store 中的评论列表追加了新条目。返回值Return TypeDisposablerequestSubscription返回一个Disposable对象用于清理订阅。其接口定义于 Disposable.mdtype Disposable { dispose: () void, };调用dispose()即取消订阅源码中即sub.unsubscriberequestSubscription.js。典型用法是在组件卸载、路由切换或业务结束时调用避免内存泄漏与多余的网络连接。行为Behavior与底层实现细节操作类型强制校验requestSubscription只接受operationKind subscription的操作否则抛出requestSubscription: Must use Subscription operation错误requestSubscription.js。这保证了你不会误把 query 或 mutation 传给该 API。environment.executeSubscription调用链订阅的实际执行委托给 Environment 的executeSubscription方法RelayModernEnvironment.jsexecuteSubscription({operation, updater}) { return this._execute({ createSource: () this.getNetwork().execute( operation.request.node.params, operation.request.variables, operation.request.cacheConfig || {}, null, ), isClientPayload: false, operation, optimisticConfig: null, updater, }); }即通过网络层拿到一个「多值响应流」的RelayObservable随后_execute会逐条规范化响应数据并提交到发布队列publish queue最后通过 Store 通知订阅了相关数据的组件重渲染。注意executeSubscription与executeMutation不同它不携带乐观更新optimisticConfig: null也不强制force: true。onNext中的 rootID 处理一个值得注意的实现细节当响应带有extensions.__relay_subscription_root_id时requestSubscription会通过createReaderSelector用该 ID 替换operation.fragment的 dataID 后再lookuprequestSubscription.js。这样即使订阅期间数据被其他操作重写onNext也能读取到正确根节点下的最新数据。测试用例reads the data using the correct rootID in onNextrequestSubscription-test.js验证了这一点并确认onNext返回的数据会在片段展开边界处截断、updater恰好被调用一次。不会覆盖已有数据requestSubscription的更新是「增量合并」而非「整体替换」测试用例does not overwrite existing datarequestSubscription-test.js展示了订阅 payload 中只包含config字段时Store 中已存在的其它字段如 fragment 展开所需的isEnabled不会被清空多次推送会在连接中依次追加Mark与Zuck两条记录。实战把requestSubscription用在真实应用中场景一组件外建立订阅useSubscription的底层其实就是requestSubscription——useSubscription.js 在useEffect中调用requestSubscription(environment, config)并在清理函数中调用dispose。因此当你需要在组件生命周期之外例如全局事件总线、Web Worker 消息、导航守卫建立订阅时直接使用requestSubscription并妥善保管返回的Disposableconst disposable requestSubscription(environment, { subscription, variables: {input}, }); // 不再需要订阅时 disposable.dispose();场景二用片段展开驱动组件刷新与其在订阅中手动挑选字段更推荐直接展开组件对应的片段例如subscription FeedbackLikeSubscription($input: FeedbackLikeSubscribeData!) { feedback_like_subscribe(data: $input) { feedback { ...FeedbackDisplay_feedback ...FeedbackDetail_feedback } } }这样每当事件流产生事件FeedbackDisplay与FeedbackDetail组件所依赖的数据都会被一并更新且相比手动重查数据单次往返即可取回全部所需字段。场景三声明式指令与deleteRecord声明式变更指令declarative mutation directives在订阅中同样生效例如删除记录subscription DeletePostSubscription($input: DeletePostSubscribeData!) { delete_post_subscribe(data: $input) { deleted_post { id deleteRecord } } }场景四配置网络层以支持订阅订阅通常通过 WebSocket 传输需要为Network.create提供第二个参数subscribe函数详见 graphql-subscriptions.mdx 的网络层配置。以graphql-ws为例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);注意事项与最佳实践updater与configs不可同时提供否则会触发 warning且configs优先被转换。务必保存并调用返回的Disposable在不需要订阅时调用dispose()防止连接泄漏。onNext的 payload 会在片段展开边界处截断若需要访问片段内部数据请通过updater读写 Store。传入 Hook 的配置对象需要记忆化useMemo否则每次渲染都会重建订阅——这一点对基于requestSubscription的封装同样适用。订阅事件流与所选字段无必然关联事件流是任意的服务端推送的 payload 与客户端选择的字段之间不存在「值一定变化」的保证Relay 只负责把收到的数据规范化并合并进 Store。延伸阅读GraphQL 订阅使用指南useSubscription/requestSubscription的完整实战讲解useSubscription 源码Hook 对requestSubscription的封装requestSubscription 源码本文引用的核心实现requestSubscription 测试覆盖RANGE_ADD、cacheConfig、updater、rootID 等行为的单元测试TypeScript 类型声明GraphQLSubscriptionConfig的精确类型store 参考文档updater中可用的 Store 读写 APIupdating-data 系列指南关于 Store 更新方式的更多说明赞分享前端开发工具【免费下载链接】relayRelay is a JavaScript framework for building>项目地址https://gitcode.com/gh_mirrors/relay29/relay点击查看免费下载相关推荐Relay requestSubscription API 深度指南以命令式方式建立 GraphQL 订阅Relay requestSubscription API 深度指南以命令式方式建立 GraphQL 订阅 requestSubscription 是 Rel前端开发工具Relay requestSubscription 命令式 GraphQL 订阅 API 完全指南Relay requestSubscription 命令式 GraphQL 订阅 API 完全指南 导读 requestSubscription 是 Relay前端开发工具Relay 18 requestSubscription 完全指南命令式建立 GraphQL 订阅的 API 详解Relay 18 requestSubscription 完全指南命令式建立 GraphQL 订阅的 API 详解 导读 requestSubscriptio前端开发工具创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考