Reputation: 127
There is a form that the user fills up with this information like email and password, than he clicks on the submit button to start a payment process. But before i let the person proceed, i need to check if the user already has an email with the same email address already in the database. When i do setRetrievedEmailAddress and set the email address that i retrieve(if it exists) to the variable retrievedEmailAddress, it does update immediately, but the second time and onwards when i click on the button that the state is changed, as can be seen in the screen shot below. I cant use useEffect hook inside an event handler, so that is out of the question. I need the state to be updated immedietly because otherwise the person will go ahead with the payment process and end up paying twice because he already has an account with us. So my question is, how do i get the state to be updated immedietly?
import React, { useState, useEffect } from 'react';
import { Link } from '@reach/router';
import { auth, database, firestore } from '../firebase';
import { generateUserDocument } from '../firebase';
import { loadStripe } from '@stripe/stripe-js';
import logo from '../images/guide_logo.png';
import './SignUp.css';
import './InputFieldStyles.css';
import { string } from 'prop-types';
import PaymentConfirmation from './PaymentConfirmation.jsx';
import "firebase/auth";
import "firebase/firestore";
import firebase from "firebase/app";
import { createImportSpecifier } from 'typescript';
import { isCompositeComponentWithType } from 'react-dom/test-utils';
const SignUp = () => {
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const [passwordre, setPasswordre] = useState('');
const [displayName, setDisplayName] = useState('');
const [error, setError] = useState(null);
const [retrievedEmailAddress, setRetrievedEmailAddress] = useState(null);
const StartPaymentProcess = async (event) => {
event.preventDefault();
database.collection("users").where("email", "==", "[email protected]")
.get()
.then((querySnapshot) => {
if (querySnapshot.exists) {}
querySnapshot.forEach((doc) => {
if (doc.exists) {
setRetrievedEmailAddress(doc.data().email);
console.log(doc.id, " => ", doc.data().email);
}
else {
console.log("doc doesnt exist");
}
});
})
.catch((error) => {
console.log("Error getting documents: ", error);
});
console.log(retrievedEmailAddress);
//This means that there user already has an account, dont move ahead and
//give error message
if (retrievedEmailAddress != null) {
setError('User Already exists, please choose a different email');
console.log("user already exists");
}
else {
//Start payment Process
}
};
const onChangeHandler = (event) => {
const { name, value } = event.currentTarget;
if (name === 'userEmail') {
setEmail(value);
setDisplayName(value);
} else if (name === 'userPassword') {
setPassword(value);
} else if (name === 'userPasswordre') {
setPasswordre(value);
if (event.target.value !== password) {
setError('Passwords do not match');
} else {
setError('');
}
}
};
const setSessionStorageValues = (event) => {
sessionStorage.setItem('email',email);
sessionStorage.setItem('password',password);
}
onkeypress = (event) => {
if (event.which === 13) {
StartPaymentProcess(event);
}
}
return (
<div
className="signup-container"
style={{
display: 'flex',
width: '100%',
height: '100%',
backgroundColor: 'white',
}}
>
<div
className="left-side"
style={{
backgroundImage:
'linear-gradient(to bottom left, #4A2C60, rgb(51,54,155,.75))',
flex: '1',
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
}}
>
<img src={logo} alt="Logo" style={{ opacity: '0.15' }} />
</div>
<div
className="right-side"
style={{
backgroundColor: 'white',
display: 'flex',
flexDirection: 'column',
flex: '1',
textAlign: 'center',
justifyContent: 'center',
alignItems: 'center',
}}
>
<div
style={{
flex: '3',
display: 'flex',
flexDirection: 'column',
justifyContent: 'space-around',
}}
>
<div className="title" style={{ justifyContent: 'space-around' }}>
<p
style={{
fontSize: '8vh',
color: '#2E3191',
marginBottom: '20px',
}}
>
Sign Up
</p>
<p style={{ fontSize: '3vh', color: 'gray' }}>
Please Enter Your Sign-up Information
</p>
</div>
</div>
<div
className="form-group"
style={{
width: '50%',
display: 'flex',
flexDirection: 'column',
flex: 5,
}}
>
<form onSubmit={(event) => {
StartPaymentProcess(event);
setSessionStorageValues(event);
}}>
<div style={{display:'inline-block'}}>
<div id="emailHeading">
Email
</div>
<input
type="email"
name="userEmail"
value={email}
placeholder="Email"
id="userEmail"
onChange={(event) => onChangeHandler(event)}
/>
<div id="passwordHeading">
Password
</div>
<input
type="password"
name="userPassword"
value={password}
placeholder="Password"
id="userPassword"
onChange={(event) => onChangeHandler(event)}
/>
</div>
<input
type="password"
name="userPasswordre"
value={passwordre}
placeholder="Password (Re-Enter)"
id="userPasswordre"
onChange={(event) => onChangeHandler(event)}
/>
<div style={{ color: 'red', fontSize: 'small' }}>{error}</div>
<div style={{ height: '30px' }} />
<button className="sign-up-button" type="submit">
Signup and Checkout
</button>
</form>
<div className="text-above-signup_button">Already have an account?</div>
<Link to="/" className="go-to-signin-page-button">Sign in here</Link>
</div>
</div>
</div>
);
};
export default SignUp;
Upvotes: 0
Views: 129
Reputation: 196
This happens because you are calling an async call so when you call you console.log(retrievedEmailAddress)
the information has not arrived yet. Therefore the best approach for you requirement is make the validation inside the answer:
database.collection("users").where("email", "==", "[email protected]")
.get()
.then((querySnapshot) => {
if (querySnapshot.exists) {}
querySnapshot.forEach((doc) => {
if (doc.exists) {
setRetrievedEmailAddress(doc.data().email);
console.log(doc.id, " => ", doc.data().email);
//here is safe to validate your data
if (doc.data().email != null) {
setError('User Already exists, please choose a different email');
console.log("user already exists");
}
else {
//Start payment Process
}
}
else {
console.log("doc doesnt exist");
}
});
})
.catch((error) => {
console.log("Error getting documents: ", error);
});
console.log(retrievedEmailAddress); // here the information will no be present the first time
Upvotes: 1
Reputation: 439
setState is async you don't get its updated value in the function you are updating it, create a state verified;
const [verified, setVerified] = useState(false);
use useEffect hook as mentioned below
useEffect(() => {
if(verified){
// proceed to payment
// ....
// at the end don't forget to setVerified(false)
}
}, [verified])
Upvotes: 0
Reputation: 11
you are using async function...
so uh should put await
keyword before request
await database.collection("users").where("email", "==", "[email protected]")
.get()
Also you are not setting retrievedEmailAddress
to null
in any case... which will be problematic
for the scenario
if (retrievedEmailAddress != null)
will be true and payment process won't start)Upvotes: 0
Reputation: 11
so, your issue is that setRetrievedEmailAddress
is taking some time to update retrievedEmailAddress
Try this...
setRetrievedEmailAddress(prevState => (doc.data().email));
Upvotes: 0