react-hook-form: isValid is sometimes false despite no errors

Describe the bug I sometimes get isValid = false despite having no visible errors and errors object being an empty object ({})

To Reproduce I do not yet have a reproducable sandbox, but I already found a code piece that might be the problem. Please see additional context

Expected behavior isValid should always reflect what the errors object contains (e.g. isValid = Object.keys(errors).length === 0)

Desktop (please complete the following information):

  • OS: Windows 10 202001
  • Browser: Microsoft Edge
  • Version: 86.0.621.0 (Official build) canary (64-bit)

Additional context The problematic line could be this code piece here: https://github.com/react-hook-form/react-hook-form/blob/03216edb0b29bae631fb752e6ec612111d82798d/src/useForm.ts#L341 which triggers revalidation but without providing an isValid parameter as the 4th parameter. Hence this line https://github.com/react-hook-form/react-hook-form/blob/03216edb0b29bae631fb752e6ec612111d82798d/src/useForm.ts#L218 will resolve in !!isValid which essentially means !!undefined === false.

AFAIK the problem only appears on async filled inputs (inputs that get their value via an api request).

About this issue

  • Original URL
  • State: closed
  • Created 4 years ago
  • Reactions: 6
  • Comments: 61 (41 by maintainers)

Commits related to this issue

Most upvoted comments

formState is wrapped with a Proxy to improve render performance and skip extra logic if the specific state is not subscribed to. Therefore make sure you invoke or read it before a render in order to enable the state update.

https://react-hook-form.com/api/useform/formstate

const { isValid } = methods.formState;

console.log(isValid);

Why is this closed when the issue still exists?

I am running into this issue too. It works with mode: 'all', reValidateMode: 'onChange', but we don’t want to trigger validations before submitting the form first.

Destructuring formState as described above also doesn’t seem to work.

So the fix for me was reading form.formState.errors before performing the trigger(), even though the errors are always empty. Reading the errors made the trigger() execute correctly and updated the form.formValues properties.

  const validateForm = async (): Promise<boolean> => {
    const _ = form.formState.errors // also works if you read form.formState.isValid
    await form.trigger()
    if (form.formState.isValid) {
      return true
    }
    if (isEmpty(form.formState.errors)) {
      console.error("Error in the form")
    } else {
      console.error(form.formState.errors)
    }
    return false
  }

hack until this is fixed.

we can assert form validity by not having errors.

isEmpty(methods.formState.errors)

for initial validation failure we can trigger validations by

 useEffect(() => {
    methods.trigger();
  }, []);

Running into this issue after updating packages on an existing app that was working as expected. Tried suggestions above with no success.

Original versions before updating (works): RHF v7.4.1 @hookform/resolvers v2.4.0 yup v0.32.9

Currently on versions (issue): RHF v7.11.0 @hookform/resolvers v2.6.1 yup v0.32.9

The form starts in a locked/disabled state (not sure if relevant). User clicks button to unlock the form. There is a Material-UI Switch component for a boolean field. It does not matter if it start as true or false. The first change of the Switch always sets isValid = false with an empty errors property.

Any following toggles of the Switch give the expected isValid = true result. The entire form always has default values. I’ve been inspecting the form values while debugging and those look fine.

The Yup validator only requires that the fields are defined - which they are in all cases as far as I can tell.

[Edit] Also worth mentioning, I have a chunk of code in the component that allows me to toggle some console logs. If I set debug = true, then this works as expected. Not sure why that is at this point.

if (debug) {
  console.log('getValues()', formContext.getValues());
  console.log('formState', JSON.parse(JSON.stringify(formContext.formState)));
}

Just another data point for analysis, I have this error when using autocomplete from my browser in an input field. When I type, no issues. When I just select the suggested option, no errors and !isValid.

Having similar issue now was there any solution

for me it is not that the functionality does not work, it is the tests that are failing when using ā€œisValidā€ in the check.

@tar-aldev which version are you using? The solution doesn’t work for me. (v7.9.0)

@bluebill1049 Sorry to spam a closed ticket, but since it has some activity. RFC: How’s the new useFieldArray rules going to play with this errors behavior and refs, currently using formState errors with { mode: 'onChange'} is far from usable, isValid is going to be true even with errors being shown on the UI, for more than a few use cases, using a trigger isn’t logical, basically means to re-execute the rules (that in my case are async ones).

Unfortunately I didn’t recognize exactly when it started to happen… When I’m back on my PC I can ā€œtime travelā€ and investigate

Here’s a simple variant with only 2 radios where isValid is initially false, but when changed it gets true: https://codesandbox.io/s/rhf-isvalid-initially-false-bug-3ucht

And here’s a variant where the fields are required. The isValid field will always be false: https://codesandbox.io/s/rhf-isvalid-always-false-bug-forked-uvb30

It seems the problem is with radios. I also use radios in my usecase where it breaks.

Putting trigger() inside of useEffect works for me!

No worriees, @GProst if you want to force the errors state to be updated/rendered, you can try to call trigger() (at useEffect), that would validate the whole form and flush down those errors state

For me doing this solved the problem

useForm<SignInFormValues>({
    resolver: yupResolver(validationSchema),
    reValidateMode: 'onChange', // this in pair with mode seems to give the expected result
    mode: 'onChange',
  })

Although I am not sure if it gives some porblems when used this way, as I am quite new to react hook form

Uff, wow šŸ˜„ Sorry for creating such hard problems. Regardless of how complicated things are though, you manage to solve them in just 30 mins of time - everytime. You’re awesome and I can’t thank you enough. The CSB works, I’d love to give it a spin in my realworld app 😃

Thank you šŸ˜—

This one is trigger and hard… https://codesandbox.io/s/rhf-isvalid-always-false-bug-forked-q1xsf?file=/src/src/useForm.ts

what happens because your radio input shares the same name, but it gets unmounted and remounted with the same name. so it was working before because we had a bug not remove field with validation correctly (rare case). I think this PR should fix this. also we doing deepEqual with validation fields with valid fields now, that’s why it’s picking up this issue.

let me know if the above CSB fix the problem. šŸ™

kk, i will take a closer look at it.

by the way, please read this: https://twitter.com/bluebill1049/status/1300231640392716288 just be careful with disabled input for submission. we are following the HTML standard in this lib.

Thanks very much, @krnlde šŸ‘ I will take a look at it tmr night.

Here I got the exact problem I have. It’s a bit tricky to force the isValid: false state, but when you just switch between the first and the second radio, it should appear after 1 second (the current timeout delay, to emulate network request). https://codesandbox.io/s/rhf-isvalid-always-false-bug-forked-xgt5u?file=/src/App.tsx

Will do! Thank you 😃

Regarding not having the mode set to onChange: Shouldn’t it be true initially anyways though?

both codesandboxs are returning true after i attached mode: 'onChange' 😃

Will do! Thank you 😃

Regarding not having the mode set to onChange: Shouldn’t it be true initially anyways though?

Hey! I have that for a while now, but it got worse somewhere between 6.4 and 6.6.

I’m not sure right now which mode I’m using, but I assume onChange.

also, both example doesn’t have mode: 'onChange', perhaps you are after one of them is checked with validate? I think required: true with each radio/checkbox is perhaps the issue here. https://codesandbox.io/s/checkbox-min-checked-5vocd

Alright! I’ll try to do a reproducable codesandbox 😃

Latest, 6.6.0. But it is the same with the previous (6.5.3)

I can go back to the point where it worked and give the version.