【问题标题】:Handling errors with react-apollo useMutation hook使用 react-apollo useMutation hook 处理错误
【发布时间】:2020-04-15 08:45:14
【问题描述】:

我一直在努力解决这个问题,但还没有找到强有力的答案。我正在尝试使用 useMutation 挂钩执行登录突变。

TLDR;我想知道options中传递的onError和useMutation给我的error之间到底有什么区别

这是我的代码 sn-p

const [login, { data, loading, error }] = useMutation(LOGIN_QUERY, {
  variables: {
    email,
    password
  },
  onError(err) {
    console.log(err);
  },
});

在服务器端,我有一个用于登录的预设/硬编码电子邮件,我没有使用 Apollo 或任何其他客户端。在此登录突变的解析器中,如果使用的电子邮件不同,我只会抛出一个错误

throw new Error('Invalid Email');

现在我想在客户端(React)处理这个错误。但我担心的是,如果我使用从 useMutation 钩子返回的“错误”并尝试以这种方式显示错误

render() {
  ...
  {error && <div> Error occurred </div>}
  ...
}

错误在 UI 中更新,但 React 立即向我显示了一个屏幕:

Unhandled Rejection (Error): Graphql error: My-custom-error-message

但是,如果我使用 onError 将 options 传递给 useMutate 函数,那么它不会显示这个屏幕,我可以做任何我想做的错误。

我想知道options 传入的onError 和useMutation 给我的error 之间到底有什么区别,为什么当onError 是未使用。

谢谢!

【问题讨论】:

    标签: reactjs graphql react-apollo apollo-client


    【解决方案1】:

    Apollo 通过其 API 公开两种错误:GraphQL 错误,作为响应的一部分返回为errors,与data 并列,以及网络错误 当请求失败时发生。当无法访问服务器或响应状态不是 200 时,将发生网络错误 - 响应中包含 errors 的查询仍然可以具有 200 状态。但是无效查询,例如,将导致 Apollo 客户端出现 400 状态和网络错误。

    Apollo Client 实际上提供了四种不同的方式来处理变异错误:

    1.) 调用钩子返回的mutate 函数会返回一个Promise。如果请求成功,Promise 将解析到一个包含服务器返回的data 的响应对象。如果请求失败,Promise 将 reject 并返回错误。这就是您在控制台中看到“Unhandled Rejection”消息的原因——您需要处理被拒绝的 Promise。

    login()
      .then(({ data }) => {
        // you can do something with the response here
      })
      .catch(e => {
        // you can do something with the error here
      })
    

    或使用 async/await 语法:

    try {
      const { data } = await login()
    } catch (e) {
      // do something with the error here
    }
    

    默认情况下,Promise 将拒绝 GraphQL 错误或网络错误。但是,通过将errorPolicy 设置为ignore 或all,Promise 将仅拒绝网络错误。在这种情况下,仍然可以通过响应对象访问 GraphQL 错误,但 Promise 会解决。

    2.) 当您提供onError 函数时,上述情况的唯一例外发生。在这种情况下,Promise 将始终解析而不是拒绝,但如果发生错误,将调用 onError 并返回结果错误。您设置的errorPolicy 也适用于此处——onError 将始终在网络错误时调用,但仅在使用 none 的默认 errorPolicy 时才会调用 GraphQL 错误。使用onError 相当于捕获被拒绝的Promise——它只是将错误处理程序从mutate 函数的调用点移动到钩子的调用点。

    3.) 除了mutate 函数,useMutation 钩子还返回一个结果对象。该对象还暴露了运行突变时遇到的任何错误。与我们上面编写的错误处理函数不同,这个error 对象代表应用程序状态。以这种方式公开的error 和data 对象都是为了方便而存在的。它们相当于这样做:

    const [mutate] = useMutation(YOUR_MUTATION)
    const [data, setData] = useState()
    const [error, setError] = useState()
    const handleClick = async () => {
      try {
        const { data } = await mutate()
        setData(data)
      catch (e) {
        setError(e)
      }
    }
    

    当您希望 UI 反映存在错误的事实时,这样的错误状态会很有用。例如,您可能会更改元素的颜色,直到突变运行没有错误。您无需自己编写上述样板文件,只需使用提供的结果对象即可。

    const [mutate, { data, error }] = useMutation(YOUR_MUTATION)
    

    注意:虽然您可以使用暴露的错误状态来更新您的 UI,但这样做不能替代实际处理错误.您必须提供onError 回调或catch 错误以避免有关未处理的Promise 拒绝的警告。

    4.) 最后,您还可以使用apollo-link-error 为您的请求添加global 错误处理。例如,这使您可以显示错误对话框,而不管请求来自应用程序的哪个位置。

    您在应用程序中使用哪些方法在很大程度上取决于您尝试执行的操作(全局与本地、状态与回调等)。大多数应用程序会使用不止一种错误处理方法。

    【讨论】:

    • 精彩而全面的解释。您获得了高票。
    • 所有这些信息都应该在 Apollo 文档中。非常详细的答案。
    • 在文档中包含这个可能很棒(:
    • 这正是我需要知道的,并展示了 Apollo 的质量和灵活性。如果您阅读文档,您会感到困惑。读到这里,你会很兴奋。
    【解决方案2】:
    const [mutationHandler, { data, loading }] = useMutation(YOUR_MUTATION, {
      onError: (err) => {
          setError(err);
      }
    });
    

    有了这个,我们可以访问具有加载状态和正确错误处理的数据,以避免控制台中的任何错误/未处理的承诺拒绝。

    【讨论】:

      猜你喜欢
      • 2021-03-11
      • 2020-04-28
      • 2018-07-09
      • 2020-01-25
      • 2018-01-28
      • 2018-08-01
      • 2019-10-02
      • 2020-04-13
      • 2017-09-24
      相关资源
      最近更新 更多