10

I have various functions in React where I need to change the state with useState then do some action conditional on whether the new state meets some criteria.

This uses a setValues method in useState to set the value of newpassword when handleChange is called with prop="newpassword". The new password is then evaluated with a regex test, and if it is valid the state variable passwordIsValid should be set to true.

const handleChange = prop => event => {
    setValues({ ...values, [prop]: event.target.value })

    if (prop === 'newpassword' && passwordValidation.test(values.newpassword)) {
      setValues({ ...values, passwordisValid: true })
      console.log(prop, values.passwordisValid)
    } else {
      console.log(prop, values.passwordisValid)
    }
  }

The state is always one step behind tho - and I know this is because useState is async, but I don't know how to use useEffect to check the state? Very new to hooks, could someone help me out?

Davtho1983
  • 3,827
  • 8
  • 54
  • 105
  • 1
    The new state will only be available in the next step. But you already knows the state will look like. Test `event.target.value` instead – Dupocas Nov 03 '19 at 17:39
  • Try to pass a callback to setValues: `setValues(currrent=>({...current,passwordIsvalid:true}))` and as Dupocas says; test event.target.value instead. – HMR Nov 03 '19 at 17:57
  • 1
    Run your conditional logics within an effect via `useEffect()` that way you keep your code clean and also you get the values coming to you closure fresh and updated. – Amin Paks Nov 03 '19 at 18:36

2 Answers2

4

useState() hook is just a function call. It returns value and function pair. values is just a constant it doesn't have any property binding.

// Think of this line
const [values, setValues] = useState(0);

// As these two lines
const values = 0;
const setValues = someFunction;

When you call setValues react updates value for the next render. Next time component renders, it will call useState again which will return new values.

As a solution you should use event.target.value. You don't want to use it directly though because event.target is nullified after you observe it.

const newValue = event.target.value
// use newValue to setValues etc
Ozan Bulut
  • 735
  • 4
  • 14
0

Inside any particular render, props and state forever stay the same and Every function inside the component render (including event handlers, effects, timeouts or API calls inside them) captures the props and state of the render call that defined it. For that reason if you try to access values.newPassword in your event handler you will always get the state for that particular render i.e the old password.

Just think of useState as a function that returns the state for that particular render and that state is immutable for that particular render.

Chitova263
  • 719
  • 4
  • 13