Skip to content

useFormState

Subscribe to form state with isolated component re-renders.

</> useFormState: (UseFormStateProps) => FormState

This custom hook allows you to subscribe to each form state, and isolate re-renders at the custom hook level. It has its own scope in terms of form state subscription, so it does not affect other useFormState or useForm hooks. Using this hook can reduce the re-render impact on large and complex form applications.

Props


NameTypeDescription
controlObjectcontrol object provided by useForm. It's optional if you are using FormProvider.
namestring | string[] Since v7.4.0 Provide a single input name, an array of them, or subscribe to all inputs' formState updates.
disabledboolean = falseSince v7.13.0 Option to disable the subscription.
exactboolean = falseSince v7.20.0 This prop will enable an exact match for input name subscriptions.

Return


NameTypeDescription
isDirtybooleanSet to true after the user modifies any of the inputs.
  • Important: make sure to provide all inputs' defaultValues at the useForm, so hook form can have a single source of truth to compare whether the form is dirty.
    const {
    formState: { isDirty, dirtyFields },
    setValue
    } = useForm({ defaultValues: { test: "" } })
    // isDirty: true ✅
    setValue('test', 'change')
    // isDirty: false because there getValues() === defaultValues ❌
    setValue('test', '')
  • File-type inputs will need to be managed at the app level due to the ability to cancel file selection and FileList object.
  • Does not support custom objects, classes, or File objects.
dirtyFieldsobjectAn object with the user-modified fields. Make sure to provide all inputs' defaultValues via useForm, so the library can compare against the defaultValues.
  • Important: make sure to provide defaultValues at the useForm, so hook form can have a single source of truth to compare each field's dirtiness.
  • dirtyFields does not necessarily match isDirty, because fields are marked dirty at the field level rather than the entire form — for example, adding or removing entries in a field array can change isDirty without any individual field in dirtyFields being marked dirty. If you want to determine the entire form state use isDirty instead.
touchedFieldsobjectAn object containing all the inputs the user has interacted with.
defaultValuesobjectSince v7.37.0 The value that was set in useForm's defaultValues or updated defaultValues via reset API.
isSubmittedbooleanSet to true after the form is submitted. Will remain true until the reset method is invoked.
isSubmitSuccessfulbooleanIndicates that the form was successfully submitted without any runtime error.
isSubmittingbooleantrue if the form is currently being submitted. false otherwise.
isLoadingbooleanSince v7.41.0 true if the form is currently loading async default values.
  • Important: this prop is only applicable to async defaultValues
    const {
    formState: { isLoading }
    } = useForm({
    defaultValues: async () => await fetch('/api')
    })
submitCountnumberThe number of times the form was submitted.
isValidbooleanSet to true if the form doesn't have any errors.
  • setError immediately forces isValid to false; this value is not itself derived from validation and will be overwritten the next time validation runs (e.g. on the next onChange, submit, or trigger() call).
  • Without a resolver or a validation mode other than the default onSubmit, isValid won't reflect actual validity until validation has run at least once (e.g. via trigger() or a submit attempt).
isValidatingbooleanSet to true during validation.
validatingFieldsobjectSince v7.51.0 Captures fields that are undergoing asynchronous validation.
errorsobjectAn object with field errors. There is also an ErrorMessage component to retrieve error messages easily.
disabledbooleanSince v7.48.0 Set to true if the form is disabled via the disabled prop in useForm.
isReadybooleanSince v7.56.0 Set to true when formState subscription setup is ready.
RULES

Returned formState is wrapped with a Proxy to improve render performance and skip extra computation if a specific state is not subscribed to; make sure you destructure or read it before rendering to enable the subscription.

const { isDirty } = useFormState() // ✅
const formState = useFormState() // ❌ should destructure the formState
Examples

import { useForm, useFormState } from "react-hook-form"
function Child({ control }) {
const { dirtyFields } = useFormState({ control })
return dirtyFields.firstName ? <p>Field is dirty.</p> : null
}
export default function App() {
const { register, handleSubmit, control } = useForm({
defaultValues: {
firstName: "firstName",
},
})
const onSubmit = (data) => console.log(data)
return (
<form onSubmit={handleSubmit(onSubmit)}>
<input {...register("firstName")} placeholder="First Name" />
<Child control={control} />
<input type="submit" />
</form>
)
}

Thank you for your support

If you find React Hook Form to be useful in your project, please consider starring and supporting it.

Edit