react-hook-form v7
Installation
npm i react-hook-form@latest // react-hook-form: "^7.0.0"
npm i @hookform/resolvers@latest // @hookform/resolvers: "^2.0.0" if you are using resolvers
npm i @hookform/devtools@latest // @hookform/devtools: "^3.0.0" if you are using devtoolsreact-hook-form v5 → v7 changes
useForm
Removed the validation prefix from config option names
The errors object was moved to become a property of the formState object
The default value of shouldUnregister was changed from false to true
const { register } = useForm({
- validationResolver: undefined,
+ resolver: undefined,
- validationContext: undefined,
+ context: undefined,
- validateCriteriaMode: "firstError",
+ criteriaMode: "firstError",
- submitFocusError: true,
+ shouldFocusError: true,
- shouldUnregister: false,
+ shouldUnregister: true, // 디폴트값이 true로 설정
})
- const { errors } = useForm();
+ const { formState: { errors } } = useForm();validationSchema → resolver
Added an options object as the third argument to resolver
npm install @hookform/resolvers- resolver: (values: any, context?: object) => Promise<ResolverResult> | ResolverResult
+ resolver: (
+ values: any,
+ context?: object,
+ options: {
+ criteriaMode?: 'firstError' | 'all',
+ names?: string[],
+ fields: { [name]: field } // Support nested field
+ }
+ ) => Promise<ResolverResult> | ResolverResultimport React from 'react';
import { useForm } from 'react-hook-form';
import { yupResolver } from '@hookform/resolvers/yup';
import * as yup from 'yup';
const schema = yup
.object()
.shape({
name: yup.string().required(),
age: yup.number().required(),
})
.required();
const App = () => {
const { register, handleSubmit } = useForm({
resolver: yupResolver(schema),
});
return (
<form onSubmit={handleSubmit(d => console.log(d))}>
<input {...register('name')} />
<input type="number" {...register('age')} />
<input type="submit" />
</form>
);
};register
The register method is no longer assigned to a ref; instead it is spread onto the input props.
return the following props: onChange, onBlur, name and ref.
-(<input ref={register({ required: true })} name="test" />) +
<input {...register('test', { required: true })} />;Apply the codemod library
npx @hookform/codemod v7/update-registerChanged the notation for accessing array-shaped objects from [] brackets to . separators.
That said, code using bracket notation still works correctly.
- test[2].test
+ test.2.testCustom register
Instead of passing a name attribute to register, just pass the name as the first argument.
-register({ name: 'test' }) + register('test');valueAs now runs before the validate function is invoked
- <input ref={register({ valueAsNumber: true, validate: (value) => parseInt(value) === 2 ) })} name="test" />
+ <input {...register('test', { valueAsNumber: true, validate: (value) => value === 2 ) }} /> // no longer need to parse againWhen destructuring register, you must call it before render and pass the values through
const { ref, ...rest } = register('test') // invoke this before render
<Input {...rest} inputRef={ref} />Controller
The API is simpler to use, and the previous props are now passed as props to the render method.
The as prop was removed, and field and fieldState are now included in the render props.
- field: onChange, onBlur, Value
- fieldState: isDirty, dirtyFields
rulesno longer supports thevalueAs*methods.
- <Controller as={Input}
- name="test"
- onChange={([_, value]) => value}
- onChangeName="onTextChange"
- onBlur={([_, value]) => value}
- onBlurName="onTextChange"
- valueName="textValue"
- />
+ <Controller name="test"
+ render={({ onChange, onBlur, value }) => {
+ return <Input
+ valueName={value}
+ onTextChange={(val) => onChange(value)}
+ onTextBlur={(val) => onBlur(value)}
+ />
+ }}
+ />
- <Controller as={<input />} />
+ <Controller render={({ field }) => <input {...field} />}
- <Controller render={(props, meta) => <input {...props} />} />
+ <Controller render={({ field, fieldState }) => <input {...field} />} />flat form option values(not support)
Returns a nested object by default
-watch({ nest: true });
+watch();
-getValues({ nest: true });
+getValues();triggerValidation → trigger
The method name was changed to trigger
The return value of trigger was changed to void
-triggerValidation();
+trigger();
-(await trigger('test')) + // Returns true|false
(await trigger('test')); // Returns voidFormContext → FormProvider
The component name was changed to FormProvider
- <FormContext {...methods}>
+ <FormProvider {...methods}>Dirty → isDirty
- const { dirty } = formState;
+ const { isDirty } = formState;dirtyFields
Changed so that you access dirtyFields as an object property rather than calling it as a method
- const { dirtyFields } = formState;
- dirtyFields.has('test');
+ const { dirtyFields } = formState;
+ dirtyFields.test;ErrorMessage
Split out from the error core library
npm install @hookform/error-messageclearError → clearErrors
-clearError('test') + clearErrors('test');setError
The logic for receiving properties was changed from arguments to an object
The logic that accepted an array as an argument to setError was removed, so it now sets only a single error
Added an options object as the third argument to setError
- setError('test', 'required', 'message')
+ setError('test', { type: 'required', message: 'message' })
- setError([ { name: 'test1', type: "max", }, { name: 'test', type: "min", } ])
+ [
+ { name: 'test1', type: "max" },
+ { name: 'test', type: "min" }
+ ].forEach(({ name, type }) => setError(name, { type }))
- setError('test', { type: 'type', message: 'issue', shouldFocus: true })
+ setError('test', { type: 'type', message: 'issue' }, { shouldFocus: true })setValue
With setValue, the dirty field is now added by default, support for multiple errors was dropped, and the logic that accepted an array was removed
-setValue('test', 'data') +
setValue('test', 'data', { shouldDirty: true }) -
setValue([{ test: '1' }, { test1: '2' }]) +
[{ name: 'test', value: 'data' }].forEach(({ name, value }) =>
setValue(name, value),
);TypedController, useTypedController(not support)
TypedController → Controller useTypedController → useController
- <TypedController
- as="textarea"
- name={['nested', 'object', 'test']}
- defaultValue=""
- rules={{ required: true }}
- />
+ <Controller
+ name={'nested.object.test'}
+ defaultValue=""
+ rules={{ required: true }}
+ render={({ field }) => <textarea {...field} />}
+ />);useFieldArray
Changed the property syntax for focus handling, added type generics, and cast the name to const during type checks (due to stricter type checking)
-append({ test: 'test' }, false);
+append({ test: 'test' }, { shouldFocus: false });
-useFieldArray<FieldArrayValues>();
+useFieldArray();
<input {...register(`test.${index}.firstName` as const)} />;touched → touchedFields
- const { touched } = formState;
+ const { touchedFields } = formState;watch
The return value of watch was changed from an object to an array
- const { test, test1 } = watch(['test', 'test1']);
+ const [test, test1] = watch(['test', 'test1']);reset
The second argument was updated to allow more detailed configuration
- reset(values, { isDirty: true })
+ // second argument is still optional
+ reset(values, {
+ keepDefaultValues: true, // new
+ keepValues: true, // new
+ keepDirty: true,
+ })