Home > Back-end >  State value not updating on form validation
State value not updating on form validation

Time:10-25

Okay so breaking down my code into chunks I have the following in HTML:

<input
    type="text"
    name="email"
    id="email"
    autoComplete="email"
    onChange={(e) => {validateField(e.target)}}
    className="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm"
/>
<FormFieldError
    Field='email'
    FormFieldErrors={formFieldErrors}
    />

The validateField function looks like this:

const validateField = (field) => {
// console.log('validatefield', field.id, field.value)
switch(field.id) {
    case 'email':
        const pattern = /[a-zA-Z0-9] [\.]?([a-zA-Z0-9] )?[\@][a-z]{3,9}[\.][a-z]{2,5}/g
        const result = pattern.test(field.value)
        if (result !== true) {
            setFormFieldErrors({...formFieldErrors, email: 'Please enter a valid email address'})
            console.log('Please enter a valid email address')
        } else {
            setFormFieldErrors({...formFieldErrors, email: null})
        }
        break

}

}

The FormFieldError function looks like this:

function FormFieldError({ Field, FormFieldErrors }) {
let message = FormFieldErrors[Field] ? FormFieldErrors[Field] : null
return (
    <>
        <div className="text-red-500 text-xs text-bold">{(message)}</div>
    </>
)

}

Now, when in the onSubmit of the form I got to the following function:

const submitNewRegistration = async (event) => {
    event.preventDefault()

    Array.prototype.forEach.call(event.target.elements, (element) => {
        validateField(element);
    })

    let errors = Object.keys(formFieldErrors).some(key => key !== null)
    console.log(errors)

}

I am declaring formFieldErrors in my state like this: const [formFieldErrors, setFormFieldErrors] = useState({})

When I am changing a field the onChange function works perfectly for each input, and if the input is wrong then the message below the input shows up thanks to the formFieldErrors displays the message underneath the input. However, when I call validateInput from my submitNewRegistration function, setFormFieldErrors doesnt seem to be called. In fact, even if I put setFormFieldErrors in to submitNewRegistration it doesnt seem to change the state of formFieldErrors. So when I am trying to validate the form just before submitting it I do not get any errors.

Can anyone explain to me why its working with the onChange method and now when I call it from submitNewRegistration ??

CodePudding user response:

It's not that setFormFieldErrors isn't called, the issue is you are trying to rely on the state value before the state has been updated. When you call setState the state doesn't update immediately. This is because setState is asynchronous, essentially a promise which resolves upon the next render of your component.

So to solve this, you need to strip your validation logic outside of the state update. In other words:

const validateField = (field) => {
// console.log('validatefield', field.id, field.value)
 switch(field.id) {
    case 'email':
        const pattern = /[a-zA-Z0-9] [\.]?([a-zA-Z0-9] )?[\@][a-z]{3,9}[\.][a-z]{2,5}/g
        const result = pattern.test(field.value)
        if (result !== true) {
            return {email: 'Please enter a valid email address'}
            console.log('Please enter a valid email address')
        } else {
            return {email: null}
        }
        break



 }

Then in your html:

<input
    type="text"
    name="email"
    id="email"
    autoComplete="email"
    onChange={(e) => {
      setFormFieldErrors({...formFieldErrors, ...validateField(e.target)})
    }
    className="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm"
/>
<FormFieldError
    Field='email'
    FormFieldErrors={formFieldErrors}
    />

And finally in the submit:

const submitNewRegistration = async (event) => {
    event.preventDefault()
    let formErrors = formFieldErrors;;
    Array.prototype.forEach.call(event.target.elements, (element) => {
        formErrors = {...formErrors, ...validateField(element)};
    })
    setFormFieldErrors(formErrors)
    let errors = Object.keys(formErrors).some(key => key !== null)
    console.log(errors)

}

  • Related