I’m developing a MERNG App, and everything is working fine so far, but i’m getting some errors in the fronted with useMutations, let me explain to you.
So, in the login/register part, if you leave fields empty or in the login, if your user is not found in the DB, it’ll give errors, and i receive those errors in the function onError(err), but, the problem is that, it gives me error always, and it said, Cannot read property ‘extensions’ of undefined, it gives that errors even if i have no errors, let me show you the code
import React, { useState } from "react"; import { useMutation, gql } from "@apollo/client"; import { useHistory } from "react-router-dom"; import { useDispatch } from "react-redux"; import { FormAuth, TitleAuth, TitleAuthImage, ContainInput, InputAuth, ContainSingleInput, ContainButtons, Button, ButtonSpan } from "../../website/Auth/AuthStyled"; import instagram from "../../img/instagram.svg"; import Loading from "../Loading/Loading"; const Login = ({ setLogin }) => { const history = useHistory(); const dispatch = useDispatch(); const [userData, setUserData] = useState({ email: "", password: "" }); const [errors, setErrors] = useState({}); const [addUser, { loading }] = useMutation(LOGIN_MUTATION, { update( _, { data: { login: data } } ) { dispatch({ type: "LOGIN", payload: data }); history.push(`/profile/${data.id}`); }, onError(err) { setErrors(err.graphQLErrors[0].extensions.exception.errors); }, variables: userData }); const handleSubmit = e => { e.preventDefault(); addUser(); setUserData({ email: "", password: "" }); }; // Framer motion animations const PopUp = { hidden: { x: 1000 }, visible: { x: 0, transition: { duration: 0.7 } } }; return ( <> {!loading ? ( <FormAuth onSubmit={handleSubmit} variants={PopUp} initial="hidden" animate="visible" > <TitleAuth> <TitleAuthImage src={instagram} /> </TitleAuth> <ContainInput> <ContainSingleInput top="2rem"> <InputAuth name="email" type="email" placeholder={errors.email ? errors.email : "Email"} maxLength="50" value={userData.email} onChange={e => setUserData({ ...userData, email: e.target.value }) } /> </ContainSingleInput> <ContainSingleInput top="7rem"> <InputAuth name="password" type="password" placeholder={errors.password ? errors.password : "Password"} maxLength="50" value={userData.password} onChange={e => setUserData({ ...userData, password: e.target.value }) } /> </ContainSingleInput> </ContainInput> <ContainButtons> <Button type="submit" Login whileHover={{ scale: 1.1 }} whileTap={{ scale: 0.85 }} > Login </Button> <ButtonSpan Register whileHover={{ scale: 1.1 }} whileTap={{ scale: 0.85 }} onClick={() => setLogin(false)} > Register </ButtonSpan> </ContainButtons> </FormAuth> ) : ( <Loading /> )} </> ); }; const LOGIN_MUTATION = gql` mutation login($email: String!, $password: String!) { login(email: $email, password: $password) { id email password token } } `; export default Login;
This is how the login looks like, the credentials are correct there
The error in the browser after clicking login
The weird part here is that, it was working before normally, but know it breaks, and i don’t know why or how, if i have errors they will appear in the input’s placeHolder, but know, it always breakes
Advertisement
Answer
According to the apollo docs onError for useMutation passes an ApolloError which contains several elements.
With your current implementation you assume there there is such a graphQLErrors
element in the onError
and that it is indeed populated with at least 1 element. This may not be the case. For that reason, when you attempt to access err.graphQLErrors[0]
you get undefined
which causes your particular error.
The docs recommend testing for evidence of a particular error before taking action:
onError(({graphQLErrors, networkError}) => { if (graphQLErrors) graphQLErrors.forEach(({message, locations, path}) => console.log( `[GraphQL error]: Message: ${message}, Location: ${locations}, Path: ${path}`, ), ); if (networkError) { console.log(`[Network error]: ${networkError}`); } });
Alternatively, you can use the built-in mechanism for tracking loading and error state
const [addUser, {loading: mutationLoading, error: mutationError}] = useMutation(LOGIN_MUTATION, { update( _, { data: {login: data} } ) { dispatch({type: "LOGIN", payload: data}); history.push(`/profile/${data.id}`); }, variables: userData });