【问题标题】:Using RxJs takeUntil() function with apollo-client将 RxJs takeUntil() 函数与 apollo-client 一起使用
【发布时间】:2017-12-22 08:40:45
【问题描述】:

我正在使用 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() 函数,即使我使用的客户端具有自己的错误处理功能。

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

谢谢

【问题讨论】:

    标签: reactjs react-apollo redux-observable apollo-client


    【解决方案1】:

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

    redux-observable 是 99.9% 只是 RxJS,所以所有操作员对 redux/actions 一无所知除了 for 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 时,我们通常只会在别无选择的情况下使用 Promises(例如,我们不控制 apollo-client API)。在这些情况下,我通常会尽快将它们包装为 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 中非常难以遵循。 “这是 Promise 捕获还是 Observable 捕获?”。当然,这只是我的看法:)


    我假设 apollo-client 没有办法实际上取消突变,因为真正的 Promise 是不可取消的。从技术上讲,此代码将忽略 Promise 的结果,而不是真正取消它(不可能)。

    【讨论】:

    • > 还有一个隔离问题。如果您将 takeUntil 放在 mergeMap 的外部,您将取消整个 Epic,而不仅仅是特定的 apollo-client 客户端。是的,我的一部分知道这一点,但将 takeUntil 放在 mergeMap juste 之后给了我一个错误,所以我想我会试一试。
    • 是的,Apollo 客户端目前无法自行取消突变。我喜欢你在第二个例子中所做的,但就像你说的那样,它不会取消突变,而只是忽略结果。我可能会尝试实现它以至少不向用户显示更改,而只是呈现他所做的最后一个动作。谢谢你的回答!
    • 最后一个问题。当我触发调度“END_LANGUAGE”的操作时,我的 languageTimeZoneEpic 不会在那之后触发。它在开始时效果很好,但是一旦我触发另一个动作来“取消”它,它就不再起作用了。有什么理由吗?谢谢@jayphelps
    • 嗯,我提供的代码不应该是这种情况——这听起来像是在顶级链上使用takeUntil 的行为,在mergeMap 之外。如果您不是复制粘贴,请三重检查您的 takeUntil 是否在正确的位置(例如,您可能在括号中偏离了一个)。在你的史诗结尾添加.do({ error: fn, complete: fn }),看看它是否出错或完成。
    • 太好了,我把它从一个括号里改了,它可以工作了!问题是我可以忽略我的查询结果,但我不能取消我调度的突变。虽然这是一个开始。再次感谢您的快速回答。顺便说一句,喜欢图书馆。 @jayphelps
    猜你喜欢
    • 1970-01-01
    • 2018-09-05
    • 2021-01-11
    • 2018-07-04
    • 2020-03-31
    • 2021-06-25
    • 2021-10-03
    • 2018-12-25
    • 1970-01-01
    相关资源
    最近更新 更多