홍승아블로그

react-hook-form v7

설치

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 devtools

react-hook-form v5 → v7 변경사항

useForm

config 파일명에 prefix에 validation 삭제 errors 객체가 formState 객체 속성으로 변경 shouldUnregister 기본 값이 false → 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

resolver 3번째 인자로 options 객체 설정 추가

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> | ResolverResult
import 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

register 메서드를 더 이상 ref에 할당하지 않고, input props에 spread 연산으로 처리해준다. return the following props: onChangeonBlurname and ref.

-(<input ref={register({ required: true })} name="test" />) +
<input {...register('test', { required: true })} />;

codemod library 적용

npx @hookform/codemod v7/update-register

배열 형태의 객체를 얻어오기 위한 문맥 처리를 [] 배열에서 . 으로 구분하도록 수정 단, 대괄호를 사용한 코드에 대해서도 정상적으로 동작은 됨

- test[2].test
+ test.2.test

Custom register register에 name attribute를 넣을 필요없이, 1번째 인자에 name 넣어주면 됩니다.

-register({ name: 'test' }) + register('test');

validate 함수 호출 전에 valueAs가 선 실행됨

- <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 again

register를 구조 분해 시 render 전에 호출해서 값을 넘겨야함

const { ref, ...rest } = register('test') // invoke this before render

<Input {...rest} inputRef={ref} />

Controller

API 사용법이 간단해졌고, 이전 props도 render method에 props로 변경됨 as prop 삭제되었고, render props에 field, fieldState가 포함되었음

  • field: onChange, onBlur, Value
  • fieldState: isDirty, dirtyFields rules에 valueAs* 메서드를 지원하지 않음.
- <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)

기본적으로 중첩된 객체를 리턴

-watch({ nest: true });
+watch();

-getValues({ nest: true });
+getValues();

triggerValidation → trigger

메서드 명이 trigger로 변경 trigger에 리턴값이 void로 변경

-triggerValidation();
+trigger();

-(await trigger('test')) + // Returns true|false
  (await trigger('test')); // Returns void

FormContext → FormProvider

컴포넌트 명이 FormProvider 변경

- <FormContext {...methods}>
+ <FormProvider {...methods}>

Dirty → isDirty

- const { dirty } = formState;
+ const { isDirty } = formState;

dirtyFields

dirtyFields method 호출이 아닌 객체 속성을 접근하도록 수정

- const { dirtyFields } = formState;
- dirtyFields.has('test');
+ const { dirtyFields } = formState;
+ dirtyFields.test;

ErrorMessage

error core 라이브러리 분리

npm install @hookform/error-message

clearError → clearErrors

-clearError('test') + clearErrors('test');

setError

속성을 받는 로직이 인자에서 객체로 변경 setError에 인자로 배열을 받는 로직 삭제되고 1개만 에러를 세팅하도록 수정 setError 3번째 인자로 옵션 설정 객체 추가

- 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

setValue 시 디폴트로 dirty 필드가 추가되었고, 여러 오류 지원 중지, 배열 받는 로직 삭제

-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

focus 처리에 대한 속성 문법 변경, 타입 제네릭 추가, name 타입 체크 시 const로 형변환(엄격한 타입 체크로 인한 처리)

-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

watch 리턴값이 객체에서 배열로 변경

- const { test, test1 } = watch(['test', 'test1']);
+ const [test, test1] = watch(['test', 'test1']);

reset

2번재 인자가 좀 상세하게 설정할 수 있도록 수정

- reset(values, { isDirty: true })
+ // second argument is still optional
+ reset(values, {
+   keepDefaultValues: true, // new
+   keepValues: true, // new
+   keepDirty: true,
+ })
이전글
Nextjs(v13)
다음글
nodejs