I'm trying to return a value from my handleRegister function, but it gives me undefined, I checked before returning the value and it exists but as soon as I return, it's undefined. Can someone please help me? The object exists:
{
"signup": {
"name": "riced",
"id": 7135,
"email": "riced#gmail.com",
"password": "U24jg2xwSbF4R6k",
"error": null,
"__typename": "User"
}
}
The following part fails:
handleRegister(this.state).then(
(data) => {
console.log(data);
return;
});
import * as React from "react"
import { navigate } from "gatsby"
import {isLoggedIn } from "../services/auth"
import fetch from 'isomorphic-fetch';
import {ApolloClient, HttpLink, InMemoryCache, gql} from '#apollo/client';
const client = new ApolloClient({
cache: new InMemoryCache(),
link: new HttpLink({
uri: 'http://10.0.0.212:9000/',
fetch
})
});
export const REGISTER_USER = gql
mutation Mutation($signupInput: SignUpInput) {
signup(signupInput: $signupInput) {
name
id
email
password
error
}
}
;
export async function handleRegister ({ username, email, password }) {
/*
if (username === `john` && password === `pass`) {
return setUser({
username: `john`,
name: `Johnny`,
email: `johnny#example.org`,
})
*/
/*
client.query({ query: ALL_USERS }).then(result => console.log(result));
*/
//let [errors, setErrors] = React.useState([]);
var gottenToken = "";
//let gottenName;
await client.mutate({ mutation: REGISTER_USER, variables: {
"signupInput": {
"name": username,
"password": password,
"email": email,
}
} }).then(result => {
console.log(result);
console.log(result.data!.signup);
//let signup = JSON.stringify(result.data!.signup);
return result.data!.signup
//Promise.resolve(result.data!.signup);
}).catch(err => {
console.log(err);
//setUser({})
//React.useEffect(() => {
//localStorage.setItem('signupError', JSON.stringify(err));
//}, [errors]);
//return haveErrorOccured("Signing up error"); // send error to browser
});
//return haveErrorOccured("Signing up error"); // send error to browser
}
class Register extends React.Component {
state = {
username: ``,
email: ``,
password: ``,
}
handleUpdate = async event => {
await this.setState({
[event.target.name]: event.target.value,
})
}
handleSubmit = async event => {
event.preventDefault()
//handleRegister(this.state)
/*
handleRegister(this.state).then(r => {
console.log(r);
}).catch(err => {
console.log(err);
});
*/
handleRegister(this.state).then(
(data) =>{
console.log(data);
return;
//return 43;
});
//console.log("signed up: " + signup);
//console.table(signup);
}
render() {
if (isLoggedIn()) {
navigate(`/app/profile`)
}
//let errorSignup;
//if(window.localStorage.getItem("signupError")){
// errorSignup = JSON.stringify(JSON.parse(window.localStorage.getItem("signupError")));
//}
//navigate("/app/register?registered", { state: { foo: "bar" }});
//<p>{errorSignup}</p>
return (
<>
<h1>Register</h1>
<form
method="post"
onSubmit={event => {
this.handleSubmit(event);
}}
>
<label>
Username
<input type="text" name="username" onChange={this.handleUpdate} />
</label>
<label>
Email
<input type="text" name="email" onChange={this.handleUpdate} />
</label>
<label>
Password
<input
type="password"
name="password"
onChange={this.handleUpdate}
/>
</label>
<input type="submit" value="Log In" />
</form>
</>
)
}
}
export default Register
Related
I'm trying to built a random football team picker and I'm doing the database myself.
I'm having a problem with the inputs
import React, { use, useRef, useState } from "react";
const fetchAll = async () => {
const getAll = await fetch("http://localhost:3000/api/getEquipos");
const data = await getAll.json();
return data;
};
const MyForm = () => {
const [newTeam, setNewTeam] = useState({
nombre: "",
logo: "",
liga: ""
})
const handleChange = (e) => {
setNewTeam({ [e.target.name]: e.target.value })
}
const data = use(fetchAll());
const handleSubmit = async (e) => {
e.preventDefault();
const lastId = await data.findLast((elem) => elem.id > 1);
try {
const addOne = await fetch("http://localhost:3000/api/addEquipos", {
method: "POST",
body: JSON.stringify({
nombre: newTeam.nombre,
logo: newTeam.logo,
liga: newTeam.liga,
id: lastId.id + 1,
}),
});
} catch (error) {
console.log(error);
}
};
return (
<div>
<form onSubmit={handleSubmit}>
<input type="text"
placeholder="equipo"
name="nombre"
onChange={handleChange} />
<input type="text"
placeholder="logo"
name="logo"
onChange={handleChange} />
<input type="text"
placeholder="liga"
name="liga"
onChange={handleChange} />
<input type="submit" value="submit" />
</form>
</div>
);
};
export default MyForm;
it's a simple form for sending my fields to my database
import dbConnect from "lib/dbConnect";
import { equipoModel } from "lib/models/equiposModel";
import { NextApiRequest, NextApiResponse } from "next";
export default async function handler(
req: NextApiRequest,
res: NextApiResponse
) {
await dbConnect();
try {
const body = JSON.parse(req.body);
console.log(body);
if (body.nombre === "") {
return;
} else {
await equipoModel.create({
nombre: body.nombre,
logo: body.logo,
liga: body.liga,
id: body.id
});
res.json({ added: true });
}
} catch (error) {
res.status(400).json(error);
}
}
and the console.log(body) shows "{ nombre: '', logo: '', liga: '', id: 3 }"
I'm trying to send the data to my database and it only shows empty strings.
It doesn't look like you're saving the Team correctly.
const handleChange = (e) => {
setNewTeam({ ...newTeam, [e.target.name]: e.target.value })
}
I recommend the new beta docs on managing state https://beta.reactjs.org/learn/managing-state
I have an issue with the login authentication in my project. I connected my react front end with my express back end, but when I try to login with valid credentials, it gets stuck in an error seems like it can't read properly the value I'm passing in my form input.
Here's my LogIn page:
import React, { Component } from 'react';
import { Link } from 'react-router-dom';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { signin } from '../actions/authAction';
import { clearErrors } from '../actions/errAction';
import { Button, Form, FormGroup, Input, Alert } from 'reactstrap'
import TopCont from '../components/TopCont'
class Signin extends Component {
state = {
email: '',
password: '',
msg: null
};
static propTypes = {
isAuth: PropTypes.bool,
signin: PropTypes.func.isRequired,
err: PropTypes.object.isRequired,
clearErrors: PropTypes.object.isRequired
};
componentDidMount(){
this.props.clearErrors();
}
componentDidUpdate(prevProps){
const { err } = this.props;
if(err !== prevProps.err) {
if(err.id === 'LOGIN_FAIL'){
this.setState({ msg: err.msg.msg });
} else {
this.setState({ msg: null });
}
}
};
onChange = e => {
this.setState({
[e.target.email]: e.target.value,
[e.target.password]: e.target.value
});
};
onSubmit = e => {
e.preventDefault();
const { email, password } = this.state;
const user = {
email,
password
};
this.props.signin(user);
/* this.props.push('/dashboard'); */
};
render() {
return (
<>
<TopCont>
<div className="signin-cont">
<h1>Accedi</h1>
{this.state.msg ? <Alert color="danger">{this.state.msg}</Alert> : null }
<Form className="signin-form-cont" onSubmit={this.onSubmit}>
<FormGroup>
<Input className="signin-form" type="email" name="email" id="email" placeholder="mario.rossi#prova.it" onChange={this.onChange}/>
</FormGroup>
<FormGroup>
<Input className="signin-form" type="password" name="password" id="password" placeholder="Password" onChange={this.onChange}/>
</FormGroup>
<Button className="sign-btn">Accedi</Button>
</Form>
<p>Non hai ancora un account? <Link to="/signup">Registrati</Link></p>
</div>
</TopCont>
</>
)
}
}
const mapStateToProps = state => ({
isAuth: state.auth.isAuth,
err: state.err
});
export default connect(mapStateToProps, { signin, clearErrors })(Signin);
Here is my Action:
import axios from 'axios';
import { returnErrors } from './errAction';
import { AUTH_ERROR, LOGIN_FAIL } from '../actions/types';
export const signin = ({ email, password }) => dispatch => {
const config = {
headers: {
'Content-Type': 'application/json'
}
};
const body = JSON.stringify({ email, password });
axios.post('/api/auth', body, config)
.then(res => dispatch({
type: LOGIN_SUCCESS,
payload: res.data
}))
.catch(err => {
dispatch(returnErrors(err.response.data, err.response.status, 'LOGIN_FAIL'));
dispatch({
type: LOGIN_FAIL
});
});
};
And here is my Auth API:
const express = require('express');
const router = express.Router();
const bcrypt = require('bcryptjs');
const config = require('config');
const jwt = require('jsonwebtoken');
const auth = require('../../middleware/auth');
const User = require('../../models/User');
//#action POST api/auth
//#descr auth user
//#access Public
router.post('/', (req, res) => {
const { email, password } = req.body
if( !email || !password ) {
return res.status(400).json({ msg: "Enter all fields."});
}
User.findOne({ email })
.then(user => {
if(!user) return res.status(400).json({ msg: "Nessun profilo trovato con questa email"});
bcrypt.compare( password, user.password )
.then(isMatch => {
if(!isMatch) return res.status(400).json({ msg: "Password errata!"});
jwt.sign(
{ id: user.id },
config.get('jwtSecret'),
{ expiresIn: 10800 },
(err, token) => {
if(err) throw err;
res.json({
token,
user: {
id: user.id,
name: user.name,
surname: user.surname,
email: user.email,
userPlus: user.userPlus
}
})
}
)
})
})
});
//#action GET api/auth/user
//#descr GET user data
//#access Private
router.get('/user', auth, (req, res) => {
User.findById(req.user.id)
.select('-password')
.then(user => res.json(user));
});
module.exports = router;
If I try to get rid of all the errors controls my server return this error:
TypeError: Cannot read property 'password' of null
The strange thing is that if I try to register a new user (with an almost identical component and server-side method) there are no problems and it authenticates too with no problems.
Someone knows how can I fix this issue?
Change your onChange Function from this:
onChange = e => {
this.setState({
[e.target.email]: e.target.value,
[e.target.password]: e.target.value
});
};
to this:
onChange = e => this.setState(prevState => ({
...prevState,
[e.target.name]: e.target.value,
}));
I have set everything in Redux side and I see every action in Redux Devtool. It works all perfect. The problem occurs when I want to dispatch action in React Component. In login component I want to dispatch action, wait its response then depending on response redirect it to a page or show errors. Here are my codes:
userActions.js
import axios from "axios";
import {
LOGIN_USER,
LOGIN_USER_SUCCESS,
LOGIN_USER_FAILED,
} from "./types";
const loginUserRequest = () => {
return {
type: LOGIN_USER,
};
};
const loginUserSuccess = (user) => {
return {
type: LOGIN_USER_SUCCESS,
payload: user,
};
};
const loginUserFailed = (error) => {
return {
type: LOGIN_USER_FAILED,
payload: error,
};
};
export const loginUser = (dataSubmitted) => {
return (dispatch) => {
dispatch(loginUserRequest());
axios
.post("/api/users/login", dataSubmitted)
.then((response) => {
dispatch(loginUserSuccess(response.data));
})
.catch((err) => {
dispatch(loginUserFailed(err));
});
};
};
userReducer.js:
import {
LOGIN_USER,
LOGIN_USER_SUCCESS,
LOGIN_USER_FAILED,
} from "../actions/types";
const initialState = {
loading: false,
user: "",
error: "",
};
export default function (state = initialState, action) {
switch (action.type) {
case LOGIN_USER:
return { ...state, loading: true };
case LOGIN_USER_SUCCESS:
return { ...state, loading: false, user: action.payload, error: "" };
case LOGIN_USER_FAILED:
return { ...state, loading: false, user: "", error: action.payload };
default:
return state;
}
}
The above codes works great and does the job. The problem is in following code where I am dispatching the async action. After I run the code I get this.props.userData as undefined.
Login.js
import React, { Component } from "react";
import { connect } from "react-redux";
import { Link } from "react-router-dom";
import { loginUser } from "../../actions/userActions";
export class Login extends Component {
state = {
email: "",
password: "",
errors: [],
};
displayErrors = (errors) =>
errors.map((error, i) => (
<div className="alert alert-danger" key={i}>
{error}
</div>
));
handleSubmit = (e) => {
e.preventDefault();
var { email, password } = this.state;
var errors = [];
if (email === "") {
errors.push("Email is required");
}
if (password === "") {
errors.push("Password is required");
}
this.setState({ errors: errors });
//Problem occurs here
this.props.dispatch(loginUser({ email, password }));
if (response.payload.success) {
sessionStorage.setItem("jwt", response.payload.token);
sessionStorage.setItem("userId", response.payload._id);
this.props.history.push("/");
} else {
errors.push("Username and/or Password is not correct");
this.setState({ errors: errors });
}
};
render() {
return (
<form className="form-signin" onSubmit={this.handleSubmit}>
<h1 className="h3 mb-3 font-weight-normal">Sign in</h1>
{this.state.errors.length > 0 && this.displayErrors(this.state.errors)}
<label for="inputEmail" className="sr-only">
Email address
</label>
<input
type="email"
id="inputEmail"
className="form-control"
placeholder="Email address"
value={this.state.email}
onChange={(e) => {
this.setState({ email: e.target.value });
}}
required
autoFocus
/>
<label for="inputPassword" className="sr-only">
Password
</label>
<input
type="password"
id="inputPassword"
className="form-control"
placeholder="Password"
value={this.state.password}
onChange={(e) => {
this.setState({ password: e.target.value });
}}
required
/>
<div className="checkbox mb-3">
<label>
<input type="checkbox" value="remember-me" /> Remember me
</label>
</div>
<button
className="btn btn-lg btn-primary btn-block"
type="submit"
onClick={this.handleSubmit}
>
Sign in
</button>
<Link to="/register">Sign Up</Link>
</form>
);
}
}
function mapStateToProps(state) {
return {
userData: state.user,
};
}
export default connect(mapStateToProps)(Login);
You need to install connected-react-router to manipulate with a history inside redux:
import { push } from 'connected-react-router';
export const loginUser = (dataSubmitted) => {
return (dispatch) => {
dispatch(loginUserRequest());
axios
.post("/api/users/login", dataSubmitted)
.then((response) => {
dispatch(loginUserSuccess(response.data));
if (response.payload.success) {
sessionStorage.setItem("jwt", response.payload.token);
sessionStorage.setItem("userId", response.payload._id);
push("/");
} else {
errors.push("Username and/or Password is not correct");
}
})
.catch((err) => {
dispatch(loginUserFailed(err));
});
};
};
As the title says, I have a check in RegistrationForm for checking if user email exists in the database. The prop is userExists. Now, if it's true, that means User email exists, so the user should be shown a message that says- "User already exists." Now, if it's false, he should be successfully registered and redirected to login.
But right now, I cannot even register with any email. In the network tab, it returns a 200 and gives
the response:
{"message":"User with this email does not exist"}
Can someone show me the proper way to do it? I mean the check, and the message from the backend, through redux, and back to the component.
My code is jibberish.
RegistrationForm Component
import React, { Component } from "react";
import { registerUser, checkValidUser } from "../../actions/userActions";
import { connect } from "react-redux";
import validator from "validator";
import { Link } from "react-router-dom";
import { toastError } from "../../../utils/toastify";
class RegistrationForm extends Component {
constructor(props) {
super(props);
this.state = {
username: "",
email: "",
password: "",
};
}
handleChange = (event) => {
const { name, value } = event.target;
this.setState({
[name]: value,
});
};
handleSubmit = async (event) => {
event.preventDefault();
const { username, email, password } = this.state;
const registrationData = {
username: this.state.username,
email: this.state.email,
password: this.state.password,
};
if (!username || !email || !password) {
return toastError("Credentials should not be empty");
}
if (username.length < 6) {
return toastError("Username should be greater than 6 characters.");
}
if (!validator.isEmail(email)) {
return toastError("Invalid email.");
}
if (password.length < 6) {
return toastError("Password must contain 6 characters.");
}
await this.props.dispatch(checkUserExists(email));
const userExists = this.props.userExists;
if (!userExists) {
this.props.dispatch(
registerUser(registrationData, () => {
this.props.history.push("/login");
})
);
} else {
toastError("User with this email already exisits"); // I'm not sure how to show the message if the user email already exists. I want to show the message from backend, but currently I'm just doing it manually
}
};
render() {
const isRegistrationInProgress = this.props.isRegistrationInProgress;
return (
<div>
<div className="field">
<p className="control has-icons-left has-icons-right">
<input
onChange={this.handleChange}
name="username"
value={this.state.username}
className="input"
type="text"
placeholder="Username"
/>
<span className="icon is-small is-left">
<i className="fas fa-user"></i>
</span>
</p>
</div>
<div className="field">
<p className="control has-icons-left has-icons-right">
<input
onChange={this.handleChange}
name="email"
value={this.state.email}
className="input"
type="email"
placeholder="Email"
/>
<span className="icon is-small is-left">
<i className="fas fa-envelope"></i>
</span>
</p>
</div>
<div className="field">
<p className="control has-icons-left">
<input
onChange={this.handleChange}
name="password"
value={this.state.password}
className="input"
type="password"
placeholder="Password"
/>
<span className="icon is-small is-left">
<i className="fas fa-lock"></i>
</span>
</p>
</div>
<div className="field">
<div className="control">
{isRegistrationInProgress ? (
<button className="button is-success is-loading">Sign Up</button>
) : (
<button onClick={this.handleSubmit} className="button is-success">
Sign up console.log("registrationData", registrationData)
</button>
)}
<Link to="/login">
<p className="has-text-danger">
Already have an account? Sign In
</p>
</Link>
</div>
</div>
</div>
);
}
}
const mapStateToProps = (state) => {
return {
isRegistrationInProgress: state.registration.isRegistrationInProgress,
userExists: state.registration.userExists,
};
};
export default connect(mapStateToProps)(RegistrationForm);
checkUserExists action
export const checkUserExists = (email) => {
return async (dispatch) => {
try {
const res = await axios.get(`${baseUrl}/users/checkUserExists/${email}`)
console.log("res=>", res)
if (res.data.message = "User with this email already exists") {
dispatch({
type: "CHECK_USER_EXISTS_SUCCESS",
})
}
} catch (err) {
console.log("error=>", err)
}
}
}
checkUserExists controller function
checkUserExists: async (req, res, next) => {
const { email } = req.params
try {
const user = await User.findOne({ email })
if (user) {
return res.status(200).json({ message: "User with this email already exists" })
} else {
return res.json({ message: "User with this email does not exist" })
}
} catch (error) {
return next(error)
}
}
registerUser action
export const registerUser = (registrationData, redirect) => {
return async (dispatch) => {
dispatch({ type: "REGISTRATION_STARTS" })
try {
const res = await axios.post(
`${baseUrl}/users/register`,
registrationData
)
dispatch({
type: "REGISTRATION_SUCCESS",
data: { user: res.data.user },
})
toastSuccess("Successfully registered")
redirect()
} catch (err) {
dispatch({
type: "REGISTRATION_ERROR",
data: { error: err },
})
}
}
}
registration reducer
const initialState = () => ({
isRegistrationInProgress: false,
isRegistered: false,
registrationError: null,
user: {},
userExists: false,
error: null,
});
const registration = (state = initialState, action) => {
switch (action.type) {
case "REGISTRATION_STARTS":
return {
...state,
isRegistrationInProgress: true,
registrationError: null,
};
case "REGISTRATION_SUCCESS":
return {
...state,
isRegistrationInProgress: false,
registrationError: null,
isRegistered: true,
user: action.data,
};
case "REGISTRATION_ERROR":
return {
...state,
isRegistrationInProgress: false,
registrationError: action.data.error,
isRegistered: false,
user: {},
};
case "CHECK_USER_EXISTS_SUCCESS":
return {
...state,
userExists: true,
error: null
};
default:
return state;
}
};
export default registration;
I want to change password, while I'm logged in.
Here's my function:
authActions.js(without catch because that will be implemented if anything start to works)
// Change password
export const changePassword = (newPassword) => (dispatch, getState) => {
// Headers
const config = {
headers: {
'Content-Type': 'application/json'
}
}
axios.post(`/api/auth/user/changePassword/`, newPassword, tokenConfig(getState))
.then(res => dispatch({
type: CHANGE_PASSWORD,
payload: res.data
}))
}
// Setup config/headers and token
export const tokenConfig = getState => {
// Get token from localstorage
const token = getState().auth.token;
// Headers
const config = {
headers: {
// "Accept": "application/json, multipart/form-data"
"Content-type": "application/json"
}
}
// If token, add to headers
if (token) {
config.headers['x-auth-token'] = token;
}
return config;
}
and authReducer.js:
...
const initialState = {
token: localStorage.getItem('token'),
isAuthenticated: false,
user: null
};
export default function (state = initialState, action) {
switch (action.type) {
...
case CHANGE_PASSWORD:
return {
...state,
token: null,
user: action.payload,
isAuthenticated: false,
isLoading: false
};
default:
return state;
}
}
and routes/api/auth.js
router.post('/user/changePassword/', (req, res) => {
console.log(req.body);
const { email, oldPassword, newPassword } = req.body
// find if old password is valid
User.findOne({ email })
.then(user => {
bcrypt.compare(oldPassword, user.password)
.then(isMatch => {
if (isMatch) {
// change to new password
user.password = newPassword
user
.save()
.then(newUser => {
res.status(200).send(newUser)
})
.catch(err => {
const message = err.message
res.status(500).json({
status: "change password failed",
msg: message
})
})
} else {
return res.status(401).send("Invalid old password")
}
})
})
.catch(err => {
res.status(500).send(err)
})
});
I have console.log(req.body); in routes just to check if anything works, but it don't works(didn't give me any message).
And component in the end(but it's not the source of problem):
import React, { useState, useEffect } from 'react';
import {
Button,
Modal,
ModalHeader,
ModalBody,
Form,
FormGroup,
Label,
Input,
NavLink
} from 'reactstrap';
import { connect } from 'react-redux';
import { changePassword } from '../../actions/authActions';
import PropTypes from 'prop-types';
const ChangePassword = ({ auth }) => {
const [modal, setModal] = useState(false);
const [enterPassword, setEnterPassword] = useState({
oldPassword: '',
newPassword: ''
});
const [takeEmail, setTakeEmail] = useState(null);
useEffect(() => {
const createArray = () => {
const { user } = auth;
setTakeEmail({ email: user.email });
};
createArray();
}, [auth.user]);
const toggle = () => {
setModal(!modal);
};
const onChange = e => {
setEnterPassword({
...enterPassword,
[e.target.name]: e.target.value
});
};
const onSubmit = (event) => {
event.preventDefault();
const { email } = takeEmail;
const { oldPassword, newPassword } = enterPassword;
console.log(enterPassword);
console.log(takeEmail);
const newUser = {
email,
oldPassword,
newPassword
}
// Add content via changePassword action
changePassword(newUser);
toggle();
}
return (
<div>
<NavLink onClick={toggle} href="#">
Change Password
</NavLink>
<Modal
isOpen={modal}
toggle={toggle}
className="open-modal"
>
<ModalHeader toggle={toggle}>Dodaj do listy ogłoszeń</ModalHeader>
<ModalBody>
<Form onSubmit={onSubmit}>
<FormGroup>
<Label for="oldPassword">Nagłówek</Label>
<Input
type="password"
name="oldPassword"
id="oldPassword"
placeholder="Wprowadź stare hasło..."
onChange={onChange}
/>
<Label for="newPassword">Nagłówek</Label>
<Input
type="password"
name="newPassword"
id="newPassword"
placeholder="Wprowadź stare hasło..."
onChange={onChange}
/>
<Button
color="dark"
style={{ marginTop: '2rem' }}
block>
Zmień hasło
</Button>
</FormGroup>
</Form>
</ModalBody>
</Modal>
</div>
);
}
ChangePassword.propTypes = {
isAuthenticated: PropTypes.bool,
changePassword: PropTypes.func.isRequired
}
const mapStateToProps = state => ({
auth: state.auth,
isAuthenticated: state.auth.isAuthenticated
});
export default connect(mapStateToProps, { changePassword })(ChangePassword);