Recommand · June 1, 2021 0

useState value is one step behind in reactjs

I am working on a login/register page in react and I use useState hooks for check if the password is strong or not. and display user what should he do to make his password stronger. But I noticed that
when user is typing in the password field their is a delay in updating the password in the useState (in the console.log() of function handlePassword) . Therefore my function handlePassword is not working properly.

  const [err,setError]=useState("")
  const [password,setPassword]=useState("")

   function handlePassword(event){
      setPassword(event.target.value);
      if(password.length<6){
        console.log(password)
        setError("password should contain 6 character")
      }else if(!isInclude(password)){
         setError("password should contain a special character")
        
      }else{
        setError("")
      }
      

    }
   <input type="password" placeholder="password" required className="form-input" value={password} onChange={handlePassword} name="password"  onClick={clearInput}/>  

There isn’t a delay, setState works asyncronously, put your console.log outside of the function and you’ll see the correct outcome. So for the same reason, you can’t check the password length right after you set the state. Instead, you need to do that in a useEffect like this;

    useEffect(()=>{
       if(password.length<6){
        console.log(password)
        setError("password should contain 6 character")
        }else if(!isInclude(password)){
         setError("password should contain a special character")
        }else{
        setError("")
        }
             }, [password])

When you trigger a state change with react, it queues up a re-render with the new state. In the case of function components, this means the function will be called again with new values for all the state values.

But variables holding existing state values from the current render do not change. So password still holds the previous password’s value, not the new one that was set by setPassword.

The short fix here is to use event.target.value instead of password when checking the length.


But it’s probably best not to have error as its own state, instead I’d calculate it from the password:

const [password,setPassword]=useState("")
const error = password.length < 6 
    ? "password should contain 6 character" 
    : !isInclude(password)
    ? "password should contain a special character"
    : "";

This avoids the need to keep the two state variables in sync.