Home > Software design >  Password States are reacting one character late
Password States are reacting one character late

Time:10-14

Im checking to see if the register forms passwords match, and when they do, something changes. but its happening on 1 "onChange" too late. Ex. User enters "DOG" as the password. when the retype it in the 2nd input, "DOG" doesnt work. but it does if they enter another character or delete one character (Ex. "DOGX" or deleting "G" so its "DO")

import React, { useState } from "react";
import { useHistory } from "react-router-dom";
import "./register.css";

function RegisterBoard() {
  const history = useHistory();
  const [register, changeRegister] = useState({
    password:       false,
    repeatPassword: false,

  });
  const [info, changeInfo] = useState({
    password: "",
    repeatPassword: "",
  });
  const changeValue = (e) => {
    const { name, value } = e.target;

    changeInfo((prev) => {
      return {
        ...prev,
        [name]: value,
      };
    });
  };

  const input = (e) => {
    const target = e.target.dataset.name;

    if (target != "repeatPassword") {
      changeRegister({
        ...register,
        [target]: true,
      });
    } else {
      if (info.password != info.repeatPassword) {
        changeRegister({
          ...register,
          repeatPassword: false,
        });
      } else {
        changeRegister({
          ...register,
          repeatPassword: true,
        });
      }
    }
  };

  return (
    <div className="registration-form">
      <form>
        <div>
          <input
            name="password"
            data-name="password"
            onChange={(e) => {
              changeValue(e);
              input(e);
            }}
            className="password"
            type="password"
            placeholder="ENTER YOUR PASSWORD HERE"
          />
          <div className="animated-button">
          </div>
        </div>
        <div>
         <input
            id="pwd"
            name="repeatPassword"
            data-name="repeatPassword"
            onChange={(e) => {
              changeValue(e);
              input(e);
            }}
            className="repeat-password"
            type="password"
            placeholder="REPEAT YOUR PASSWORD HERE"
          />
         </div>
        </div>
      </form>
    </div>
  );
}
export default RegisterBoard;

CodePudding user response:

You're definitely going to want to implement a useEffect here to update the UI every time the password & repeatPassword state changes, to ensure that after the last character is typed that you get the full password. Inside the useEffect is where you'll write your conditional logic. What I provided is just a good example...

import React, { useState, useEffect } from "react";
import { useHistory } from "react-router-dom";
import "./register.css";

function RegisterBoard() {
  const history = useHistory();
  const [password, setPassword] = useState('')
  const [repeatPassword, setRepeatPassword] = useState('')
  //const [register, changeRegister] = useState(false);

  const changeValue = (e) => {
    const { name, value } = e.target.value;

  const input = (e) => {
    const target = e.target.dataset.name;

    if (target != "repeatPassword") {
      changeRegister({
        ...register,
        [target]: true,
      });
    } else {
      if (info.password != info.repeatPassword) {
        changeRegister({
          ...register,
          repeatPassword: false,
        });
      } else {
        changeRegister({
          ...register,
          repeatPassword: true,
        });
      }
    }
  };


useEffect(() => {
    
    if((password !== "" && repeatPassword !== "") && (password !== 
       repeatPassword)){

         console.log("PASSWORDS DO NOT MATCH!!!")

    }

   console.log(password, repeatPassword)

  }, [password, repeatPassword])

  return (
    <div className="registration-form">
      <form>
        <div>
          <input
            name="password"
            data-name="password"
            onChange={(e) => changeValue(e)}
            className="password"
            type="password"
            placeholder="ENTER YOUR PASSWORD HERE"
          />
          <div className="animated-button">
          </div>
        </div>
        <div>
         <input
            id="pwd"
            name="repeatPassword"
            data-name="repeatPassword"
            onChange={(e) => changeValue(e)}
            className="repeat-password"
            type="password"
            placeholder="REPEAT YOUR PASSWORD HERE"
          />
         </div>
        </div>
      </form>
    </div>
  );
}
export default RegisterBoard;

CodePudding user response:

I guess this is because you are calling both 'changeValue' and 'input' functions within the inputs onChange attribute. Since they are firing at the same time, 'input' is not using the most recent value for 'info', because 'changeValue' hasn't set the new state yet.

Either call the input function within a useEffect hook which is dependent on changes to 'info's' state, or use e.target.value instead of info's state within the 'input' function to compare info.password != info.repeatPassword

EDIT: here is the useEffect way, it simplifies it and you can remove your input function completely: https://codesandbox.io/s/jolly-khorana-8s63b?file=/src/App.js

import React, { useState, useEffect } from "react";
import "./styles.css";

function RegisterBoard() {
  const [register, changeRegister] = useState({
    password: false,
    repeatPassword: false
  });
  const [info, changeInfo] = useState({
    password: "",
    repeatPassword: ""
  });

  const changeValue = (e) => {
    const { name, value } = e.target;

    changeInfo((prev) => {
      return {
        ...prev,
        [name]: value
      };
    });
  };

  useEffect(() => {
    let password = false;
    let repeatPassword = false;
    if (info.password !== "") {
      password = true;
      if (info.password === info.repeatPassword) {
        repeatPassword = true;
      }
    }
    changeRegister({ password, repeatPassword });
  }, [info]);

  return (
    <div className="registration-form">
      <form>
        <div>
          <input
            name="password"
            data-name="password"
            onChange={changeValue}
            className="password"
            type="password"
            placeholder="ENTER YOUR PASSWORD HERE"
          />
          <div className="animated-button"></div>
        </div>
        <div>
          <input
            id="pwd"
            name="repeatPassword"
            data-name="repeatPassword"
            onChange={changeValue}
            className="repeat-password"
            type="password"
            placeholder="REPEAT YOUR PASSWORD HERE"
          />
        </div>
      </form>

      <div>{info.password}</div>
      <div>{info.repeatPassword}</div>
      <div>{register.repeatPassword ? "match" : "don't match"}</div>
    </div>
  );
}

export default function App() {
  return (
    <div className="App">
      <RegisterBoard />
    </div>
  );
}

  • Related