What is the best way to handle the user input errors returned from GraphQL resolver? I am trying to code user singup using react and graphql. I would like to user errors like email is taken or some other validation message on the form.
Currently I am getting the following on browser window
Unhandled Runtime Error Error: Objects are not valid as a React child (found: Error: Error: Email already taken). If you meant to render a collection of children, use an array instead.
React Component
import React, { useState } from "react";
import { gql, useMutation } from "@apollo/client";
import Form from "./styles/form";
import Router from "next/router";
const SIGNUP_MUTATION = gql`
mutation SIGNUP_MUTATION(
$email: String!
$password: String!
$name: String!
) {
signup(email: $email, password: $password, name: $name) {
email
username
password
profile
token
}
}
`;
const SignupComponent = () => {
const [values, setValues] = useState({
email: "",
name: "",
password: "",
error: "",
loading: false,
message: "",
showForm: true,
});
const { name, email, password, message, showForm } = values;
const handleChange = (name) => (e) => {
setValues({ ...values, error: false, [name]: e.target.value });
};
const showLoading = () =>
loading ? <div className="alert alert-info">Loading...</div> : "";
const showError = () =>
error ? <div className="alert alert-danger">{error}</div> : "";
const showMessage = () =>
message ? <div className="alert alert-info">{message}</div> : "";
const [signup, { loading, error }] = useMutation(SIGNUP_MUTATION, {
variables: {
email: email,
password: password,
name: name,
},
});
const handleSubmit = async (e) => {
e.preventDefault();
try {
await signup();
if (error) {
setValues({ ...values, loading: true, error: true });
}
} catch (err) {
console.log(err);
}
if (error) {
setValues({
...values,
loading: false,
error: error,
showForm: true,
message: "",
});
} else {
setValues({
...values,
loading: false,
error: "",
showForm: false,
message: " Signup successful. Please signin",
});
}
};
const signupForm = () => {
return (
<div>
<Form method="post" onSubmit={handleSubmit}>
<fieldset>
<h2>Sign Up for An Account</h2>
<div className="form-group">
<input
value={name}
onChange={handleChange("name")}
type="text"
className="form-control"
placeholder="Type your name"
/>
</div>
<div className="form-group">
<input
value={email}
onChange={handleChange("email")}
type="email"
className="form-control"
placeholder="Type your email"
/>
</div>
<div className="form-group">
<input
value={password}
onChange={handleChange("password")}
type="password"
className="form-control"
placeholder="Type your password"
/>
</div>
<div>
<button className="btn btn-primary">Signup</button>
</div>
</fieldset>
</Form>
</div>
);
};
return (
<>
{showError()}
{showLoading()}
{showMessage()}
{showForm && signupForm()}
</>
);
};
export default SignupComponent;
Resolver
Mutation: {
signup: async (__, { email, password, name }) => {
try {
const user = await userService.signup({
name,
email,
password,
});
const token = await jwt.sign({ _id: user._id }, APP_SECRET);
const { profile, userName } = user;
const authtype = {
token,
username: userName,
password,
name,
email,
profile,
};
return authtype;
} catch (error) {
// throw new Error(error)
throw error;
}
},
You shouldn't use object in {}
. error
is object type, not a string so should transform it into a string type for render.