Q-man
Q-man

Reputation: 127

How can i get useState to update immediately

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?

enter image description here

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

Answers (4)

vi calderon
vi calderon

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

Arfan ali
Arfan ali

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

Muhammad Bilal
Muhammad Bilal

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

  • user input email id that already exist (email stored in retrievedEmailAddress) then
  • user input email id that doesnot exist (but retrievedEmailAddress not updated so if (retrievedEmailAddress != null) will be true and payment process won't start)

Upvotes: 0

Muhammad Bilal
Muhammad Bilal

Reputation: 11

so, your issue is that setRetrievedEmailAddress is taking some time to update retrievedEmailAddress

Try this...

setRetrievedEmailAddress(prevState => (doc.data().email));

Upvotes: 0

Related Questions