在 apollo-client 中使用 RxJs takeUntil() 函数

Using RxJs takeUntil() function with apollo-client

我正在使用 Apollo-Client 对我的 GraphQL 服务器进行查询和修改。由于 Apollo 有自己的错误处理,因此实现 takeUntil 函数来取消我的查询调用和我的突变要困难得多。

使用 Apollo,我的突变如下所示:

export const languageTimeZoneEpic = (action$) => {
  return action$.ofType(CHANGE_LANGUAGE)
    .mergeMap(action => client.mutate({
      mutation: languageMutation,
      variables: { id: action.id,  language: action.selected_language }
    }).then(result => changeLanguageFulfilled(result))
      .catch(error => changeLanguageError(error))
  );
};

我的突变没有问题,如果有错误,它会捕获它。 这里的问题是,如果我像下面的示例一样添加 takeUntil() 函数,我的函数就根本不起作用了。

export const languageTimeZoneEpic = (action$) => {
  return action$.ofType(CHANGE_LANGUAGE)
    .mergeMap(action => client.mutate({
      mutation: languageMutation,
      variables: { id: action.id,  language: action.selected_language }
    }).then(result => changeLanguageFulfilled(result))
      .catch(error => changeLanguageError(error))
  ).takeUntil("END_LANGUAGE");
};

我想知道是否有一种方法可以使用 takeUntil() 函数,即使我使用的客户端有自己的错误处理功能。

*如果我在 mutation 完成之前发送另一个动作,这里的 takeUntil() 将被调用。

谢谢

takeUntil 不接受字符串作为其参数。相反,它期望一个它将订阅的 Observable,使用第一个 next'd 值作为信号。

redux-observable 99.9% 只是 RxJS,所以所有操作符对 redux/actions 除了 对于 ofType 是唯一的操作符 redux-observable提供--其余的都是 RxJS 内置的。

还有一个隔离问题。如果您将 takeUntil 放在 mergeMap 的外面,您将取消整个 Epic,而不仅仅是特定的 apollo-client 客户端。相反,我们需要将它 放在 mergeMap 中,并且因为我们正在处理一个 Promise,所以我们需要使用 Observable.from 来包装它。

export const languageTimeZoneEpic = (action$) => {
  return action$.ofType(CHANGE_LANGUAGE)
    .mergeMap(action =>
      Observable.from(
        client.mutate({
          mutation: languageMutation,
          variables: { id: action.id,  language: action.selected_language }
        })
        .then(result => changeLanguageFulfilled(result))
        .catch(error => changeLanguageError(error))
      )
        .takeUntil(action$.ofType('END_LANGUAGE'))
    );
};

然而,像这样使用 Promise thencatch 可以说是不合适的——如果你更喜欢使用 Promises,我可能会建议不要使用 redux-observable。当使用 redux-observable 时,如果我们别无选择(例如,我们不控制 apollo-client API),我们通常只会使用 Promises。在这些情况下,我通常会尽快将它们包装成一个 Observable,然后剩下的就是普通的 RxJS。

export const languageTimeZoneEpic = (action$) => {
  return action$.ofType(CHANGE_LANGUAGE)
    .mergeMap(action =>
      Observable.from(client.mutate({
        mutation: languageMutation,
        variables: { id: action.id,  language: action.selected_language }
      }))
        .map(result => changeLanguageFulfilled(result))
        .catch(error => Observable.of(
          changeLanguageError(error)
        ))
        .takeUntil(action$.ofType('END_LANGUAGE'))
    );
};

这有时意味着它更冗长,但主要是关于不使用 Promise 的 catch,因为这会使您的代码很难在 redux-observable 中遵循。 "is this Promise catch or Observable catch?"。当然,这只是我的看法:)


我假设 apollo-client 没有办法实际上取消一个突变,因为真正的 Promise 是不可取消的。这段代码在技术上只会忽略 Promise 的结果,而不是真正取消它(不可能)。