react-hook-form: V7: formState.isDirty is not set to true onChange if value is watched

Describe the bug In v7 in a form with only one input the formState.isDirty will not be true when the input is changed if you are watching the form value. It will become true once the input is blurred, however this is not good if the save button is disabled when !form.isDirty as it prevents the user from submitting the form unless they have blurred the input.

If you remove the watch on the form value it works as expected

To Reproduce Create a form with a single input and set the submit button to be disabled if !formState.isDirty

  1. Watch a field with something similar to what is below or in the codeSandbox
function Form(){
  const { register, formState, watch } = useForm()
  const { isDirty } = formState

  const name = watch('name')
  return <form>
    <input type='text' {...register('name')} />
    <button type='submit' disabled={!isDirty}>Save</button>
  </form>
}
  1. Change the field value
  2. The submit button will be disabled when it should be enabled

Codesandbox link (Required) https://codesandbox.io/s/react-hook-form-useform-template-forked-rpm8c?file=/src/index.js

About this issue

  • Original URL
  • State: closed
  • Created 3 years ago
  • Comments: 15 (8 by maintainers)

Commits related to this issue

Most upvoted comments

You want to set the shouldDirty flag to true in the third options argument of setValue.

You can learn more at RHF setValue method docs

setValue('name', 'value', { shouldDirty: true })

Brilliant thanks, that works! thanks for the pointer in the docs too.

You want to set the shouldDirty flag to true in the third options argument of setValue.

You can learn more at RHF setValue method docs

setValue('name', 'value', { shouldDirty: true })

I’m glad I could help!

Ahha - right, it works now. Thank you.

thanks @Moshyfawn 🙏

@tombburnell, works fine in the latest version: see this CSB

Hi, Your example doesn’t contain an onChange() handler on the input field. If you add one like below, then the isDirty flag is not updated until the focus changes away from the edited field. regards, Tom

function titleChange(e: any) { console.log(“Title changed”, e.target?.value); }

return (

  <form onSubmit={handleSubmit(onSubmit)}>
    <input {...register("firstName")} placeholder="First Name" onChange={titleChange}/>
    <pre>
      <code>First Name: {firstName || "''"}</code>
    </pre>
    <button disabled={!isDirty} type="submit">
      Submit
    </button>
  </form>
</div>

);

By spreading all the register props to your input via {...register("field")} and passing your onChange handler after, you’re re-assigning the input’s onChange which is used by RHF.

Please, assign your onChange handler as a second options argument to register instead.

<input
  {...register("name", {
+   onChange: titleChange
  })}
-   onChange={titleChange}
/>