使用钩子处理Graphql中错误的常用方法

时间:2019-09-20 06:40:59

标签: react-hooks react-apollo

在使用阿波罗graphql的渲染道具方式中。我曾经能够做到这一点:

export const CsmartQuery = (({ children, isShowGenericErrorSnackBarForError, ...rest }) => (
  <Query errorPolicy="all"
         {...rest} >
      {result =>
        <GraphQLErrorHandler isShowGenericErrorSnackBarForError={isShowGenericErrorSnackBarForError}
                             result={result}>
          {(transformedResult) => children(transformedResult)}
        </GraphQLErrorHandler>
      }
  </Query>
))

我的GraphQLErrorHandler,用于检查错误,如果它是服务器错误(我的通用捕获所有错误),那么我向用户显示错误小吃栏。我还会处理该错误,清除所有不需要的内容,并仅将代码和消息发送给与他们一起工作的孩子。这是完整的GraphQLErrorHandler组件

import React from 'react';
import { showErrorSnackBarAction } from '../redux/appActions'
import { connect } from 'react-redux'


const transformError = (e) => {
  if(e.networkError ||
    ((e.graphQLErrors || []).length === 0) ||
    !e.graphQLErrors[0].extensions ||
    e.graphQLErrors[0].extensions.code === 'SERVER_ERROR') {
    return {
      message: 'An error occurred while processing your request. Please try again',
      code: 'SERVER_ERROR'
    }
  }
  return {
    message: e.graphQLErrors[0].message,
    code: e.graphQLErrors[0].extensions.code,
  }
};

const transformErrorsInResult = (result) => {
  return {...result, error: result.error ? transformError(result.error) : undefined}
}

const GraphQLErrorHandler = ({result, isShowGenericErrorSnackBarForError, showErrorSnackBarAction, children}) => {
  const [transformedResult, setTransformedResult] = React.useState(transformErrorsInResult(result))
  React.useEffect(() => {
    const newResult = transformErrorsInResult(result)
    if(newResult.error && isShowGenericErrorSnackBarForError) {
      showErrorSnackBarAction({message: newResult.error.message})
    }
    setTransformedResult(() => newResult)
  }, [result, isShowGenericErrorSnackBarForError, showErrorSnackBarAction])
  return (
    children(transformedResult)
  )
}

export default connect(null, { showErrorSnackBarAction })(GraphQLErrorHandler);

而且我不使用来自阿波罗的查询,也不在任何地方使用CsmartQuery组件。

<CsmartQuery query={companyAddressQuery} variables={{ companyId: company.id }} isShowGenericErrorSnackBarForError>
  {({ data, loading, error }) => {
    if (error) return null
    if (loading)
      return (
        <Container textAlign="center">
          <Loader active />
        </Container>
      )
    return <AddressDetailsWrapper companyAddresses={data.companyAddresses || []} company={company} {...rest} />
  }}
</CsmartQuery>

如何使用useQuery挂钩并能够以一般方式处理错误?我希望将错误转换,并在需要时显示小吃店。最好,我不必在每个组件中都重复代码。

1 个答案:

答案 0 :(得分:0)

这就是我着手做的。创建了一个包装所有阿波罗钩子的自定义钩子

export const useCsmartQuery = (query, queryVariables, isShowGenericErrorSnackBarForError = true) => {
  const queryResult = useQuery(query, queryVariables)
  const { error } = queryResult
  const dispatch = useDispatch()
  if (error) {
    const transformedError = transformError(error)
    if (isShowGenericErrorSnackBarForError) {
      dispatch(showErrorSnackBarAction({ message: transformedError.message }))
    }
  }
  return queryResult
}

export const useCsmartMutation = (mutation, mutationData, isShowGenericErrorSnackBarForError = true) => {
  const [callMutation, mutationResult] = useMutation(mutation, mutationData)
  const { error } = mutationResult
  const dispatch = useDispatch()
  if (error) {
    const transformedError = transformError(error)
    if (isShowGenericErrorSnackBarForError) {
      dispatch(showErrorSnackBarAction({ message: transformedError.message }))
    }
    return [callMutation, {...mutationResult, error: transformedError }]
  }
  return [callMutation, mutationResult]
}

现在到处使用自定义钩子。