React Hook Form의 핵심 개념 중 하나는 컴포넌트를 react-hook-form의 useForm() 훅에 연결하는 것이다.
import { useForm, SubmitHandler } from "react-hook-form";
interface FormProps {
name: string;
gender: 'male' | 'female';
}
const UserForm = () => {
const { register, handleSubmit } = useForm<FormProps>();
const onSubmit: SubmitHandler<FormProps> = (data) => {
console.log(data);
};
return (
<form onSubmit={handleSubmit(onSubmit)}>
<label>Name
<input {...register('name')} /> // 각각의 register에는 FormProps의 속성이 들어있다.
</label>
<label>
Gender Selection
<select {...register('gender')} >
<option value='female'>female</option>
<option value='male'>male</option>
</select>
</label>
<input type='submit' />
</form>
);
}
export default UserForm;
useForm
react-hook-form의 핵심 함수 중 하나로, 폼 관련 로직을 초기화하고 관리하는 데 사용된다. 다양한 옵션을 받아와 폼의 동작을 설정할 수 있다.
register
입력 요소를 react-hook-form으로 등록하는 역할을 한다. 등록된 입력 요소는 handleSubmit함수와 함께 사용되어 폼의 제출 및 유효성 검사를 처리한다. 객체와 연동되어 등록된 입력 요소는 name속성을 기반으로 자동으로 관리된다.
handleSubmit
폼 제출 시 실행될 함수를 래핑하는 역할을 한다. 폼 데이터의 유효성 검사와 상태 업데이트를 자동으로 처리하여 개발자가 제출 로직에 집중할 수 있도록 도와준다.
사용자가 인풋값을 적절한 형식에 맞게 입력했는지 체크해주는 역할을 한다. 예를 들어 아래와 같이 이름칸은 필수이자 최대 길이는 20이고, 비밀번호는 필수이자 최소 길이를 8자로 지정하는 등이 있다.
....
<input {...register('firstName', { required: true, maxLength: 20 })} />
<input {...register('lastName', { pattern: /^[A-Za-z]+$/i })} /> // 정규표현식 가능
<input type="number" {...register('age', { min: 20, max: 25 })} />
....
이러한 유효성 검사에 어긋나면 실시간으로 사용자에게 에러를 출력해주는 방법이다. submit 버튼을 누르고 난 다음 지속적으로 에러를 출력한다. 이 부분은 개발자가 옵션으로 커스텀하게 변경할 수 있다.
const { register, handleSubmit, formState: { errors } } = useForm<FormProps>();
...
<>
<input type='number' {...register('age', { required: true, min: 20, max: 30 })}/>
{
errors.age?.type === 'required' && (
<span style={{ color: 'red' }}>Age is required</span>
)
}
{
errors.age?.type === 'min' && (
<span style={{ color: 'red' }}>Minimum age is 20</span>
)
}
{
errors.age?.type === 'max' && (
<span style={{ color: 'red' }}>Maximun age is 30</span>
)
}
</>



react로 웹 앱을 개발하면서, 사용자와 상호작용하는 form은 대개 외부 UI 라이브러리를 활용하여 디자인하거나, styled-component 를 활용한 디자인을 사용한다. react-hook-form는 이러한 부분 역시 지원해주고 있다.
기존의 태그 부분을, 다음과 같이 Controller 컴포넌트의 render 부분에 작성해주면 된다. 아래 예제에서는 material ui의 <Input /> 컴포넌트를 넣어주었다.
import { useForm, Controller, SubmitHandler } from 'react-hook-form';
import { Input } from '@mui/material';
....
<Controller
name='age'
control={control}
defaultValue={33}
rules={{ required: true, min: 20, max: 30 }}
render={({ field, fieldState }) => (
<Input {...field} placeholder='age...'/>
)}
/>
Controller 태그의 속성은 다음과 같다.
name (필수)
해당 필드의 name을 지정한다. react-hook-form의 폼 데이터와 연결된다.
control (필수)
react-hook-form의 control 객체를 전달한다. control은 폼의 제어 및 상태를 관리하는 데 사용된다.
defaultValue
입력 컨트롤러의 초기값을 설정한다. react-hook-form에서 폼 데이터의 초기값을 설정하려면 useForm 훅의 defaultValues 속성을 사용하는 것이 좋다.
rules
유효성 검사 규칙을 정의한다. 기존의 register 에서 두 번째 인자로 설정하던 부분과 동일하다.
shouldUnregister
컨트롤러가 언마운트될 때 react-hook-form에서 등록을 해제할지 여부를 설정한다. 기본값은 false이며, 언마운트시에 등록을 해제하지 않는다.
render
외부 컨트롤러를 렌더링할 JSX를 반환하는 함수이다. 이 부분에 외부 UI의 컴포넌트를 작성해준다. render 속성은 field 객체를 전달받아 사용한다. 이를 입력 컴포넌트에 {...field} 로 먼저 넣어준다.
