我想在 @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
并停止在全局级别显示错误通知。
我还试图通过在
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);
})
我希望这可以帮助任何人。就我而言,我做了以下事情:
在我正在执行查询的组件上:
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。