your code actually updates state 3 times. It's not the spread operator guilt, but the fact you are passing the same error object state to each state update, and that error has no errors.

This way, each subsequent state update overwrites the previous one with the outdated state error, where it doesn't have any errors.

In these situations to reach the desired outcome you must pass a callback function to setErrors. That callback will receive as argument the current state.

if you change each setErrors:

setErrors({ ...errors, name: 'You must enter your name.' })

to receive a callback:

setErrors(errors => ({ ...errors, name: 'You must enter your name.' }))

You will see that your errors state will update correctly, since the callback function receives the current state object.

Note: Obviously @CertainPerformance is a much cleaner code.


While you could use callbacks instead, eg

setErrors(errors => ({ ...errors, // ...

it looks like it would be a lot easier to call setErrors only once:

  // if these are the only properties,
  // no need for `...errors`
  name: === '' ? 'You must enter your name.' : '',
  email: === '' ? 'You must enter a valid email.' : '',
  password: user.password === '' ? 'You must enter a password.' : '',

If this is in a <form>, you could also consider adding a required attribute instead of checking all these manually.

Related Query

More Query from same tag