如何防止 Apollo 客户端 useQuery 中的错误传播?

问题描述 投票:0回答:2

我想在 @apollo/react-hook 中使用

useQuery
时捕获组件级别的错误并防止传播。 这是我的示例代码

const invitationDocument = gql`
   query DecodeInvitation($token: String!) {
       DecodeInvitation(token: $token) {
          name
          email
       }
   }
`
const InvitationPage = (props) => {
    const { data, error, loading } = useQuery(invitationDocument, {variables: { token: "XXXX" }});

    if(error)
    {
        return <InvitationErrorPage error={error.message}/>
    }

    return loading? <LoadingPage> : <InvitationAcceptPage />
}

它工作正常,但同时,错误正在传播到其父级别,因此我收到来自全局级别的错误处理程序的另一条错误通知消息。 在应用程序级别,我使用 apollo-link-error 来管理 Graphql 错误。

import { onError } from 'apollo-link-error';
const errorLink = onError (({ graphqlErrors, networkError }) => {
    if(graphqlErrors)
       notification.error(graphqlErrors[0].message);
});
const client = ApolloClient({
   cache: new InMemoryCache(),
   link: ApolloLink.from([
            errorLink,
            new HttpLink({ uri: `http://localhost:8080/graphql`})
          ])
})

目前,我正在寻找一种解决方案来停止传播到顶层,以便我只能显示

InvitationErrorPage
并停止在全局级别显示错误通知。

error-handling graphql apollo react-apollo apollo-client
2个回答
4
投票

我还试图通过在

useQuery
钩子上处理错误来防止错误被记录在错误链接中,进一步深入研究 ApolloLink 文档有助于弄清楚正在发生的事情。关键的误解是错误链接不是父级或应用程序级处理程序,而是请求中间件。考虑数据如何从服务器返回是有帮助的:

因此,当您从错误链接看到错误通知时,它并不是从

useQuery
挂钩“向上传播”的内容:它发生在请求路径中
useQuery
结果在客户端可用之前。

因此,错误链接的

onError
回调将始终在
useQuery
钩子中的任何错误处理代码之前被调用。

也许您最好的选择是使用

operation
graphQLErrors[x].extensions
的组合来找出应该通过错误链接中间件传递哪些错误,如下所示:

const errorLink = onError(({operation, response, graphQLErrors}) => {
  if (!graphQLErrors) {
    return;
  }
  if (operation.operationName === "DecodeInvitation") {
    for (const err of graphQLErrors) {
      if (err.extensions?.code === 'UNAUTHENTICATED') {
        // Return without "notifying"
        return;
      }
    }
  }
  // Notify otherwise
  notification.error(graphqlErrors[0].message);
})

0
投票

我希望这可以帮助任何人。就我而言,我做了以下事情:

在我正在执行查询的组件上:

const { data, loading } = useQuery({
            variables: { ...whatever variable },
            context: { errorHandledLocally: true }, // We don't want to handle this error globally
            onError: (error) => {
                // Do whatever you want with the error
                // In my case I want to show a toast with an specific error
            }
    })

然后,在apollo客户端中,我有以下链接:

const errorLink = onError(({ graphQLErrors, networkError, operation }) => {
        if (graphQLErrors) {
            graphQLErrors.map(({ message }) => Sentry.captureMessage(message))
            if (operation.getContext().errorHandledLocally) return // Check this into the queries performed throughout the app

            toaster.negative(default_error)
        }

        if (networkError) {
            toaster.negative(network_error)
            Sentry.captureException(networkError)
        }
    })

基本上使用标志 errorHandledLocally 我确保在这种情况下我不会渲染两个 toast。

© www.soinside.com 2019 - 2024. All rights reserved.