在redux-saga中使用@apollo/client的ApolloClient.subscribe的最佳实践与合理性问询
使用Redux-Saga结合Apollo Client GraphQL订阅的实践问题
问题
- 实现该需求是否存在最佳实践?
- 这种做法是否属于对redux-saga或@apollo/client的误用?
预期实现逻辑示例
function* rootSaga () { yield fork(watchAccountBalance) } function* watchAccountBalance () { // @todo 创建订阅 // @todo 订阅的每次变更结果作为`balance`传入 if (balance == 0.00) { yield put(notifyBalanceEmpty()); } }
如果无法实现上述逻辑,现有庞大代码库将不得不添加大量React Hooks,在useSubscription响应变更时向redux-saga派发动作。
已尝试的实现代码
function* subscribeAccountBalance() { const apolloClient: ApolloClient<NormalizedCacheObject> = yield call(getClient); const subscription = yield call([apolloClient, apolloClient.subscribe], { query: USER_BALANCE_SUBSCRIPTION, }); console.log(TAG, 'subscription', {subscription}); }
得到的输出:
LOG home/saga subscription {"subscription": {"_subscriber": [Function anonymous]}}
解答
1. 最佳实践
有明确可行的最佳实践,核心是在Redux-Saga中处理Apollo订阅的异步流:
- 适配Observable流:Apollo的
subscribe返回Observable对象,可通过其自带的异步迭代器特性,在Saga中直接消费推送数据。 - 拆分逻辑职责:把订阅创建、数据处理、取消订阅拆分为独立Saga,保证代码可维护性。
- 处理取消场景:在Saga被取消时主动终止订阅,避免内存泄漏。
完整实现示例:
import { take, call, put, cancelled, fork } from 'redux-saga/effects'; import { ApolloClient, NormalizedCacheObject } from '@apollo/client'; // 处理订阅推送的具体业务逻辑 function* handleAccountBalanceUpdates(subscriptionObservable) { try { // 将Observable转为异步迭代器,逐个获取推送结果 const iterator = subscriptionObservable[Symbol.asyncIterator](); while (true) { const { value } = yield call([iterator, iterator.next]); const balance = value.data.userBalance; if (balance === 0.00) { yield put(notifyBalanceEmpty()); } } } finally { // Saga取消时终止订阅 if (yield cancelled()) { subscriptionObservable.unsubscribe(); } } } // 监听账户余额的订阅Saga function* watchAccountBalance() { const apolloClient: ApolloClient<NormalizedCacheObject> = yield call(getClient); const subscription = apolloClient.subscribe({ query: USER_BALANCE_SUBSCRIPTION, }); // 启动子Saga处理订阅流 yield fork(handleAccountBalanceUpdates, subscription); } function* rootSaga() { yield fork(watchAccountBalance); }
2. 是否属于误用?
完全不属于误用。Redux-Saga的核心就是处理异步流和事件驱动逻辑,Apollo Client负责GraphQL数据的实时获取,两者结合职责清晰:
- Redux-Saga集中管理业务规则(比如余额为0触发通知),避免业务逻辑分散在组件中,适合大型代码库的维护。
- Apollo Client专注于数据层的订阅与缓存,没有越界承担业务逻辑。
相比在组件中用useSubscription再派发Action的方案,这种实现更符合大型项目的架构设计,能保持组件的UI聚焦,同时让所有事件驱动逻辑统一在Saga中,便于调试和维护。
内容的提问来源于stack exchange,提问作者matabeitt
相关产品推荐
相关产品推荐

