Issue
what i’m trying to do is to signup my user using simple form ,but suddenly i get this error also it seems that data (promise argument ) is undefined ,
Unhandled Runtime Error
TypeError: Cannot read property ‘message’ of undefined
(forgive my terminology)
frontend
import React,{useState} from "react";
import {signup} from '../../actions/auth'
const SignupComponent = () =>{
const [values, setValues] = useState({
name: "Fares",
email: "[email protected]",
password: "dccihdss",
error: "",
loading: false,
message: "",
showForm: true,
});
const {name,email,password,error,loading,message,showForm} = values
const handleSubmit = (e)=>{
e.preventDefault();
setValues({...values,loading:true,error:false})
const user ={name,email,password}
signup(user)
.then(data => {
console.log(data); //!!!!!!!this promise is returning 'undefined' , !!!!!!!!!!!!
if(data.error){
setValues({...values,error:data.error,loading:false});
}else{
setValues({
...values,
name: "",
email: "",
password: "",
error: "",
loading: false,
message: data.message,
showForm: false,
});
}
});
}
const handleChange = name => e => {
setValues({ ...values, error:false, [name]: e.target.value });
}
const signupForm = () =>{
return (
<form onSubmit={handleSubmit}>
<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>
</form>
);
}
return (
<React.Fragment>{signupForm()}</React.Fragment>
)
};
export default SignupComponent;
signup method (isomorphic-fetch)
import fetch from 'isomorphic-fetch';
import {API} from '../config'
export const signup = (user)=>{
return fetch(`${API}/signup`, {
method: "POST",
headers: {
Accept: "application/json",
"Contnet-Type": "application/json",
},
body: JSON.stringify(user)
}).
then((response) => {
return response.json();
}).catch((error) => console.log(error));
}
Auth API
exports.signup = (req, res) => {
user.findOne({ email: req.body.email }).exec((err, user) => {
if (user) {
return res.status(400).json({
error: "Email is taken",
});
}
const { name, email, password } = req.body;
let username = shortId.generate();
let profile = `${process.env.CLIENT_URL}/profile/${username}`;
let newUser = new User({ name, email, password, profile, username });
newUser.save((err, success) => {
if (err) {
return res.status(400).json({
error: "something is not correct",
});
}
res.json({
// user:success,
message: "Signup success ! please Sign in ",
});
});
});
};
exports.signin = (req, res) => {
const { email, password } = req.body;
//check if the user exist
User.findOne({ email }).exec((err, user) => {
if (err || !user) {
return res.status(400).json({
error: "User with that email does not exist , Please signup",
});
}
//authentification
if(!user.authenticate(password)){
return res.status(400).json({
error: "Email and password don't match",
});
}
// generate token and send to client
const token = jwt.sign({ _id: user._id },process.env.JWT_SECRET,{expiresIn:'1d'});
res.cookie("token", token, { expiresIn: "1d" });
const {_id,username,name,email,role} = user
return res.json({
token,
user:{_id,username,name,email,role}
})
});
};
// FrontEnd dependencies
"dependencies": {
"es6-promise-promise": "^1.0.0",
"isomorphic-fetch": "^3.0.0",
"next": "^10.1.2",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"reactstrap": "^8.9.0"
},
backend dependencies
"dependencies": {
"body-parser": "^1.19.0",
"cookie-parser": "^1.4.5",
"cors": "^2.8.5",
"dotenv": "^8.2.0",
"express": "^4.17.1",
"express-jwt": "^6.0.0",
"express-validator": "^6.10.0",
"jsonwebtoken": "^8.5.1",
"mongoose": "^5.12.2",
"morgan": "^1.10.0",
"nodemon": "^2.0.7",
"shortid": "^2.2.16"
}
Solution
Your signup method is an asynchronous call, it should return a promise. If you are already handling .then
call in your handleSubmit
method, then you need to remove the .then
call from the signup method. Below is the updated code
import fetch from 'isomorphic-fetch';
import {API} from '../config'
// now, since fetch returns a promise, and signup method is returning fetch
// it is returning a promise on which we can call `.then` and `.catch` accordingly
export const signup = async (user) => {
return fetch(`${API}/signup`, {
method: "POST",
headers: {
Accept: "application/json",
"Contnet-Type": "application/json",
},
body: JSON.stringify(user)
})
}