Search code examples
reactjsinputstateonchange

updating state based on numbers and characters in passwords react


I am trying to create some password validation UI for practice in react. Meaning the credentials for a password to be valid appear in red initially, and as the user creates their password they are validated and they turn green. Normal password conditions such as: password contains an uppercase, a number, a special character.

Here is the state that holds all the keys to my validation:

  const [valid, setValid] = useState({
    uppercase: false,
    specialChar: false,
    number: false
  });

an input value controlled by an input state:

  const [input, setInput] = useState("");

        <input
          type="text"
          className={validated ? "valid" : "not-valid"}
          value={input}
          onChange={(e) => handleChange(e.target.value)}
        />

my handleChange function which calls a validator function

  const handleChange = (e) => {
    setInput(e);
    validateNums(e);
  };

everything up to this point is fine. The code fails during my validateNums function. It can work with either of the if statements but not with both of them there. What is going wrong here and why?

  const validateNums = (param) => {
    for (const num in nums) {
      if (param.includes(num)) {
        setValid({ ...valid, number: true });
      } else if (param.indexOf(num) === -1) {
        setValid({ ...valid, number: false });
      }
    }
  };


also linking sandbox: https://codesandbox.io/s/frosty-cache-6pmn8?file=/src/App.js:551-807


Solution

  • Your second validate function will simply override your state with an old valid state that did not take your just changed valid state into account (that you changed with validateNums). If you would run the validateNums-function after your validateCaps-function, you will notice that the Number-validation works, but the Caps-validation does not as expected.

    There are different approaches to achieve what you want, e.g. with a promise based call; if you would like to make sure to run your validate functions one after the other. In your specific case of a simple input validation this is not needed at all: The simplest, you take your param and set the valid state one time. Please see the validate function.

    const validateNums = (param) => nums.some((num) => param.includes(num));
    const validateCaps = (param) => caps.some((cap) => param.includes(cap));
    
    const validate = (params) => {
      setValid({
        ...valid,
        number: validateNums(params),
        uppercase: validateCaps(params)
      });
    };
    
    const handleChange = (e) => {
      setInput(e);
      validate(e);
    };
    

    You see, that I simplified as well your validateNums and your validateCaps. A tip: Checkout whether there wouldn't be other ways to check for numbers or caps.

    Please find your adapted sandbox here: https://codesandbox.io/s/hopeful-brook-1wfu2?file=/src/App.js