Manipulando erros com o uso do react-apollo

10

Eu tenho tentado resolver esse problema, mas não encontrei uma resposta forte. Estou tentando executar uma mutação de logon usando o gancho useMutation.

TLDR; Quero saber qual é exatamente a diferença entre o onError passado nas opções e o erro que o useMutation me forneceu

Aqui está o meu trecho de código

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

No lado do servidor, tenho um e-mail predefinido / codificado usando o login e não estou usando o Apollo ou qualquer outro cliente. No resolvedor dessa mutação de login, eu simplesmente lançarei um erro se o email não for o mesmo usando

throw new Error('Invalid Email');

Agora eu quero lidar com esse erro no lado do cliente (React). Mas minha preocupação é que se eu usar o 'erro' retornado do gancho useMutation e tentar mostrar o erro dessa maneira

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

o erro é atualizado na interface do usuário, mas imediatamente React mostra uma tela com Rejeição sem tratamento (erro): Graphql error: My-custom-error-message

Mas, se eu usar onError transmitido em opções para usar a função Mutate, ele não me mostrará essa tela e eu posso fazer o que quiser com o erro.

Quero saber qual é exatamente a diferença entre o onError passado nas opções e o erro que o useMutation me forneceu e por que o React me mostra essa tela de erro quando o onError não é usado.

Obrigado!

d_bhatnagar
fonte

Respostas:

33

O Apollo expõe dois tipos de erros por meio de sua API: erros do GraphQL , que são retornados como parte da resposta e errors, ao lado data, e erros de rede que ocorrem quando uma solicitação falha. Ocorrerá um erro de rede quando um servidor não puder ser alcançado ou se o status da resposta for diferente de 200 - as consultas que tiverem errorsna resposta ainda poderão ter o status 200. Mas uma consulta inválida, por exemplo, resultará em um status 400 e um erro de rede no Apollo Client.

O Apollo Client realmente oferece quatro maneiras diferentes de lidar com erros de mutação:

1.) Chamar a mutatefunção retornada pelo gancho retorna uma promessa. Se a solicitação for bem-sucedida, a Promessa resolverá para um objeto de resposta que inclui o dataretornado pelo servidor. Se a solicitação falhar, a Promessa rejeitará o erro. É por isso que você vê uma mensagem "Rejeição não tratada" no console - é necessário lidar com a promessa rejeitada.

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

ou com sintaxe assíncrona / aguardada:

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

Por padrão, a Promise rejeitará em qualquer erros GraphQL ou erros de rede. Ao definir a errorPolicy como ignoreou all, no entanto, a Promessa apenas rejeitará erros de rede. Nesse caso, os erros do GraphQL ainda estarão acessíveis através do objeto de resposta, mas a Promise será resolvida.

2.) A única exceção ao acima ocorre quando você fornece uma onErrorfunção. Nesse caso, a promessa sempre será resolvida em vez de rejeitada, mas se ocorrer um erro, onErrorserá chamada com o erro resultante. oerrorPolicy conjunto definido também se aplica aqui - onErrorsempre será chamado para erros de rede, mas somente para erros do GraphQL ao usar o padrão errorPolicyde none. Usar onErroré equivalente a capturar a Promessa rejeitada - apenas move o manipulador de erros do site de chamada da mutatefunção para o site de chamada do gancho.

3.) Além da mutatefunção, o useMutationgancho também retorna um objeto de resultado. Este objeto também expõe quaisquer erros encontrados ao executar a mutação. Diferentemente das funções do manipulador de erros que escrevemos acima, esse errorobjeto representa o estado do aplicativo . Tanto o erroredata objetos expostos neste exist maneira como uma conveniência. Eles são equivalentes a fazer isso:

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)
  }
}

Ter um estado de erro como esse pode ser útil quando você deseja que sua interface do usuário reflita o fato de que há um erro. Por exemplo, você pode alterar a cor de um elemento até que a mutação seja executada sem erro. Em vez de ter que escrever o padrão acima, você pode usar o objeto de resultado fornecido.

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

NOTA: Embora você possa usar o estado de erro exposto para atualizar sua interface do usuário, isso não substitui a manipulação real do erro. Você deve fornecer um onErrorretorno de chamada ou catcho erro para evitar avisos sobre uma rejeição de promessa não tratada.

4.) Por fim, você também pode usar o apollo-link-error para adicionar um tratamento global de erros às suas solicitações. Isso permite, por exemplo, exibir uma caixa de diálogo de erro, independentemente de onde a solicitação foi originada no aplicativo.

Qual desses métodos você utiliza em seu aplicativo depende muito do que você está tentando fazer (global x local, estado x retorno de chamada etc.). A maioria dos aplicativos fará uso de mais de um método de tratamento de erros.

Daniel Rearden
fonte
Obrigada pelo esclarecimento ! Voto a favor!
Hyphæne Ohmen
Explicação impressionante e abrangente. Você ganhou um voto positivo elevado.
David Fernandez