0

Whenever i hit my sign in button with empty email and password fields, my code should update my emailError state and passwordError with Some message but it is only updating passwordError state.

const validateSignIn = () => {
    let errorCount = 0;
    const emailExp = /^[a-zA-Z0-9+_.-]+@[a-zA-Z0-9.-]+$/
    const Passwordexp = /^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])(?=.*?[#?!@$%^&*-]).{8,}$/

    const validEmail = emailExp.test(loginDetails.email)
    const validPassword = Passwordexp.test(loginDetails.password)
    console.log(validEmail, validPassword)
    console.log(loginDetails)
    if (loginDetails.email == "") {
      setLoginDetails({ ...loginDetails, emailError: "Email cannot be left empty"})
      errorCount = errorCount + 1
    }
    else if (validEmail == false) {
      setLoginDetails({ ...loginDetails, emailError : "Invalid email address"})
      errorCount = errorCount + 1
    }

    if (loginDetails.password == "") {
      setLoginDetails({ ...loginDetails, passwordError: "Password field cannot be left Empty" })
      errorCount = errorCount + 1
    }
    else if (validPassword == false) {
      setLoginDetails({ ...loginDetails,passwordError: "Invalid Password" })
      errorCount = errorCount + 1
    }

    if (errorCount == 0) {
          navigation.replace('dashboard')
    }
}
Drew Reese
  • 165,259
  • 14
  • 153
  • 181
  • Does this answer your question? [The useState set method is not reflecting a change immediately](https://stackoverflow.com/questions/54069253/the-usestate-set-method-is-not-reflecting-a-change-immediately) – Martin Apr 12 '22 at 05:46

1 Answers1

0

This issue is that each enqueued update is updating from the same stale loginDetails state that's closed over in callback scope. The last update processed is the one that is set and available on the next render.

Use functional state updates if enqueueing multiple updates to the same state in the same function scope. The allows updating from the previous state value instead of the value closed over in scope.

const validateSignIn = () => {
  let errorCount = 0;
  const emailExp = /^[a-zA-Z0-9+_.-]+@[a-zA-Z0-9.-]+$/;
  const Passwordexp = /^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])(?=.*?[#?!@$%^&*-]).{8,}$/;

  const validEmail = emailExp.test(loginDetails.email);
  const validPassword = Passwordexp.test(loginDetails.password);
  console.log(validEmail, validPassword);
  console.log(loginDetails);
  if (loginDetails.email == "") {
    setLoginDetails((loginDetails) => ({ // <-- function is passed previous state
      ...loginDetails,
      emailError: "Email cannot be left empty"
    }));
    errorCount = errorCount + 1;
  } else if (validEmail == false) {
    setLoginDetails((loginDetails) => ({
      ...loginDetails,
      emailError: "Invalid email address"
    }));
    errorCount = errorCount + 1;
  }

  if (loginDetails.password == "") {
    setLoginDetails((loginDetails) => ({
      ...loginDetails,
      passwordError: "Password field cannot be left Empty"
    }));
    errorCount = errorCount + 1;
  } else if (validPassword == false) {
    setLoginDetails((loginDetails) => ({
      ...loginDetails,
      passwordError: "Invalid Password"
    }));
    errorCount = errorCount + 1;
  }

  if (errorCount == 0) {
    navigation.replace("dashboard");
  }
};

A suggested improvement would be to create a local errors object and set error properties on it, then either enqueue a single state update or navigate.

const validateSignIn = () => {
  const errors = {};

  const emailExp = /^[a-zA-Z0-9+_.-]+@[a-zA-Z0-9.-]+$/;
  const Passwordexp = /^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])(?=.*?[#?!@$%^&*-]).{8,}$/;

  const validEmail = emailExp.test(loginDetails.email);
  const validPassword = Passwordexp.test(loginDetails.password);

  if (!loginDetails.email) {
    errors.emailError = "Email cannot be left empty";
  } else if (!validEmail) {
    errors.emailError = "Invalid email address";
  }

  if (!loginDetails.password) {
    errors.passwordError = "Password field cannot be left Empty";
  } else if (!validPassword) {
    errors.passwordError = "Invalid Password";
  }

  if (Object.values(errors).length) {
    setLoginDetails(loginDetails => ({
      ...loginDetails,
      ...errors,
    }))
  } else {
    navigation.replace("dashboard");
  }
};
Drew Reese
  • 165,259
  • 14
  • 153
  • 181