Manejo de errores con react-apollo use Mutation hook

10

He estado tratando de entender este problema, pero no he encontrado una respuesta sólida. Estoy tratando de ejecutar una mutación de inicio de sesión utilizando el enlace useMutation.

TLDR; Quiero saber cuál es exactamente la diferencia entre las opciones onError pasadas y el error que me dio useMutation

Aquí está mi fragmento de código

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

En el lado del servidor, tengo un correo electrónico preestablecido / codificado utilizado para iniciar sesión y no estoy usando Apollo ni ningún otro cliente. En la resolución de esta Mutación de inicio de sesión, simplemente lanzo un error si el correo electrónico no es el mismo usando

throw new Error('Invalid Email');

Ahora quiero manejar este error en el lado del cliente (Reaccionar). Pero mi preocupación es que si uso el 'error' devuelto por el enlace de useMutation e intento mostrar el error de esta manera

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

el error se actualiza en la interfaz de usuario pero inmediatamente Reaccionar me muestra una pantalla con rechazo no controlado (error): error Graphql: mensaje de error personalizado

Pero, si uso onError pasado en las opciones para usar la función Mutar, entonces no me muestra esta pantalla y puedo hacer lo que quiera con el error.

Quiero saber cuál es exactamente la diferencia entre el onError pasado en las opciones y el error que me dio useMutation y por qué React me muestra esa pantalla de error cuando no se usa onError .

¡Gracias!

d_bhatnagar
fuente

Respuestas:

33

Apollo expone dos tipos de errores a través de su API: errores GraphQL , que se devuelven como parte de la respuesta como errors, junto data, y errores de red que ocurren cuando falla una solicitud. Se producirá un error de red cuando no se pueda acceder a un servidor o si el estado de la respuesta es distinto de 200; las consultas que figuran errorsen la respuesta pueden tener un estado de 200. Sin embargo, una consulta no válida, por ejemplo, generará un estado 400 y un error de red en Apollo Client.

Apollo Client en realidad proporciona cuatro formas diferentes de manejar los errores de mutación:

1.) Llamar a la mutatefunción devuelta por el enlace devuelve una Promesa. Si la solicitud es exitosa, la Promesa se resolverá en un objeto de respuesta que incluye el datadevuelto por el servidor. Si la solicitud falla, la promesa se rechazará con el error. Esta es la razón por la que ve un mensaje de "Rechazo no controlado" en la consola: debe manejar la Promesa rechazada.

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

o con sintaxis asíncrona / espera:

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

De forma predeterminada, Promise rechazará tanto los errores de GraphQL como los errores de red. Sin embargo, al establecer errorPolicy en ignoreo all, Promise solo rechazará los errores de red. En este caso, los errores de GraphQL seguirán siendo accesibles a través del objeto de respuesta, pero la Promesa se resolverá.

2.) La única excepción a lo anterior ocurre cuando proporciona una onErrorfunción. En este caso, la Promesa siempre se resolverá en lugar de rechazar, pero si se produce un error, onErrorse llamará con el error resultante. Lo errorPolicyque establezca también se aplica aquí: onErrorsiempre se solicitará errores de red, pero solo se invocará con errores GraphQL cuando se use el valor predeterminado errorPolicyde none. Usar onErrores equivalente a atrapar la Promesa rechazada: solo mueve el controlador de errores del sitio de llamada de la mutatefunción al sitio de llamada del enlace.

3.) Además de la mutatefunción, el useMutationgancho también devuelve un objeto de resultado. Este objeto también expone los errores encontrados al ejecutar la mutación. A diferencia de las funciones del controlador de errores que escribimos anteriormente, este errorobjeto representa el estado de la aplicación . Tanto el errory dataobjetos expuestos esta manera existen para su conveniencia. Son equivalentes a hacer esto:

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

Tener un estado de error como este puede ser útil cuando desea que su IU refleje el hecho de que hay un error. Por ejemplo, puede cambiar el color de un elemento hasta que la mutación se ejecute sin un error. En lugar de tener que escribir usted mismo la plantilla anterior, puede usar el objeto de resultado proporcionado.

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

NOTA: Si bien puede usar el estado de error expuesto para actualizar su IU, hacerlo no es un sustituto para manejar el error. Usted debe proporcionar ya sea una onErrordevolución de llamada o catchel error con el fin de evitar las advertencias sobre un rechazo no controlada promesa.

4.) Por último, también puede usar apollo-link-error para agregar un manejo de errores global para sus solicitudes. Esto le permite, por ejemplo, mostrar un cuadro de diálogo de error independientemente de en qué parte de su aplicación se originó la solicitud.

Cuál de estos métodos utiliza en su aplicación depende en gran medida de lo que está tratando de hacer (global frente a local, estado frente a devolución de llamada, etc.). La mayoría de las aplicaciones utilizarán más de un método de manejo de errores.

Daniel Rearden
fuente
Gracias por la explicación ! ¡Votado!
Hyphæne Ohmen
Impresionante y completa explicación. Te has ganado un alto voto.
David Fernández hace