React Hook Form
작성
- 간단하고 효율적인 폼 관리 라이브러리로, 입력 상태를 따로 설정하지 않아도 쉽게 폼 데이터를 관리할 수 있다.
npm install react-hook-form
2. 기본 구조
-
가장 기본적인 폼을 예제로 만들어보자.
-
useForm훅을 이용해register,handleSubmit,errors객체를 생성하는 게 핵심이야.import React from 'react'; import { useForm } from 'react-hook-form'; function SimpleForm() { const { register, handleSubmit, formState: { errors } } = useForm(); const onSubmit = (data) => { console.log(data); }; return ( <form onSubmit={handleSubmit(onSubmit)}> <div> <label>Username</label> <input {...register("username", { required: true })} /> {errors.username && <p>This field is required</p>} </div> <button type="submit">Submit</button> </form> ); } export default SimpleForm;register: 각 input 요소를 관리하고, 폼 데이터에 연결해주는 메서드.handleSubmit: 폼의 제출을 처리하고,onSubmit함수를 실행하게 함.errors: 각 필드의 유효성 검사를 도와주는 객체로, 필드에 오류가 있을 때 메시지를 출력할 수 있어.
3. 유효성 검사 추가하기
더 많은 검증을 추가하여 예제를 확장해보자. 예를 들어, minLength와 같은 조건을 추가할 수 있어.
<input
{...register("username", { required: true, minLength: 5 })}
/>
{errors.username?.type === "required" && <p>This field is required</p>}
{errors.username?.type === "minLength" && <p>Minimum length is 5</p>}
- 필드에 여러 조건을 붙일 수 있어서 유효성 검사와 에러 처리가 간편해.
4. 폼 초기값 설정하기
폼에 초기값을 설정할 때는 defaultValues 속성을 useForm 안에 설정해주면 돼.
const { register, handleSubmit, formState: { errors }, reset } = useForm({
defaultValues: {
username: "initialUsername",
}
});
5. 제어 컴포넌트와 비제어 컴포넌트
React Hook Form은 비제어 컴포넌트 방식으로 폼 데이터를 처리해 최적화가 가능해. 만약 제어 컴포넌트를 사용하고 싶다면 Controller 컴포넌트를 이용할 수 있어.
import { Controller } from 'react-hook-form';
<Controller
name="controlledInput"
control={control}
defaultValue=""
render={({ field }) => <input {...field} />}
/>
요약
React Hook Form은 register, handleSubmit, errors를 이용해 기본적인 폼을 간단하게 관리하고, 비제어 컴포넌트를 기본으로 해서 성능을 최적화해. 유효성 검사, 초기값 설정 등도 쉽게 적용할 수 있어서 편리한 폼 관리가 가능하지.
이제 추가적인 기능을 살펴보면서 더 복잡한 폼도 관리할 수 있는 방법을 알아볼게.
1. useFieldArray
useFieldArray는 동적으로 필드 배열을 다룰 때 유용해. 예를 들어, 여러 개의 전화번호나 주소를 입력할 때 사용할 수 있어.
import { useForm, useFieldArray } from "react-hook-form";
function DynamicForm() {
const { register, control, handleSubmit } = useForm({
defaultValues: {
phones: [{ number: "" }]
}
});
const { fields, append, remove } = useFieldArray({
control,
name: "phones"
});
const onSubmit = (data) => console.log(data);
return (
<form onSubmit={handleSubmit(onSubmit)}>
{fields.map((field, index) => (
<div key={field.id}>
<input
{...register(`phones.${index}.number`)}
placeholder="Phone Number"
/>
<button type="button" onClick={() => remove(index)}>
Remove
</button>
</div>
))}
<button type="button" onClick={() => append({ number: "" })}>
Add Phone
</button>
<button type="submit">Submit</button>
</form>
);
}
export default DynamicForm;
fields: 배열 형태로 필드들을 관리해.append: 새 필드를 추가.remove: 특정 필드를 삭제.
2. useFormContext
useFormContext는 상위 컴포넌트에서 선언한 useForm을 하위 컴포넌트에서도 사용할 수 있도록 해줘. 특히 큰 폼을 여러 컴포넌트로 나누어 관리할 때 유용해.
import { useForm, FormProvider, useFormContext } from "react-hook-form";
function FormInput({ name }) {
const { register } = useFormContext();
return <input {...register(name)} />;
}
function MainForm() {
const methods = useForm();
const onSubmit = (data) => console.log(data);
return (
<FormProvider {...methods}>
<form onSubmit={methods.handleSubmit(onSubmit)}>
<FormInput name="firstName" />
<FormInput name="lastName" />
<button type="submit">Submit</button>
</form>
</FormProvider>
);
}
export default MainForm;
FormProvider:useFormContext를 통해 폼 데이터와 메서드를 하위 컴포넌트로 전달.useFormContext: 현재 폼 데이터를 접근하도록 도와줘.
3. Control
Control은 useFieldArray와 Controller 같은 고급 메서드에 필요한 객체로, 폼의 상태와 메서드를 컨트롤하는 역할을 해.
import { useForm, Controller } from "react-hook-form";
function ControlledInputForm() {
const { control, handleSubmit } = useForm();
const onSubmit = (data) => console.log(data);
return (
<form onSubmit={handleSubmit(onSubmit)}>
<Controller
name="controlledInput"
control={control}
defaultValue=""
render={({ field }) => <input {...field} />}
/>
<button type="submit">Submit</button>
</form>
);
}
export default ControlledInputForm;
Controller: 제어 컴포넌트를 사용할 때control을 통해 데이터를 관리해.
4. FieldValues
FieldValues는 TypeScript에서 폼 필드들의 타입을 표현하기 위한 기본 타입으로, 폼 데이터를 유연하게 정의할 수 있게 해줘.
import { useForm, SubmitHandler, FieldValues } from "react-hook-form";
function TypedForm() {
const { register, handleSubmit } = useForm<FieldValues>();
const onSubmit: SubmitHandler<FieldValues> = (data) => console.log(data);
return (
<form onSubmit={handleSubmit(onSubmit)}>
<input {...register("username")} placeholder="Username" />
<button type="submit">Submit</button>
</form>
);
}
export default TypedForm;
FieldValues: 각 필드의 타입을 표현할 수 있게 도와줘서, 타입 검사와 코드의 안전성을 높여.
핵심 요약
useFieldArray는 배열 필드를 동적으로 관리하고, useFormContext는 폼 컨텍스트를 컴포넌트들 사이에서 공유하며, Control은 Controller와 같은 고급 기능을 지원해줘. FieldValues는 TypeScript에서 필드들의 타입을 유연하게 관리할 때 사용해.
대본 스타일로 간결하게 설명하면서 자연스럽게 코드와 예시를 함께 들어볼게.
라디오 대본: React Hook Form 주요 메서드와 추가 기능 소개
DJ: 반가워요, 여러분! 오늘은 React Hook Form의 주요 메서드와 몇 가지 유용한 추가 기능들까지 전해드릴게요. 폼 작업할 때 자주 만나게 될 친구들이죠. 시작할 준비 되셨나요? 자, 먼저 가장 기본적인 메서드부터 하나씩 만나봅시다.
1. useForm - 기본 세팅
DJ: 먼저 useForm 훅이에요. 모든 시작이 여기서부터라고 할 수 있어요. useForm을 호출하면 register, handleSubmit, errors 등 핵심 도구들이 나와요. 각각이 폼의 필드와 상태를 관리하는데, 예제로 한번 볼게요.
import { useForm } from 'react-hook-form';
function MyForm() {
const { register, handleSubmit, formState: { errors } } = useForm();
const onSubmit = (data) => console.log(data);
return (
<form onSubmit={handleSubmit(onSubmit)}>
<input {...register("username", { required: true })} />
{errors.username && <p>Username is required</p>}
<button type="submit">Submit</button>
</form>
);
}
DJ: 보셨죠? register는 input을 폼에 등록하고, handleSubmit은 제출할 때 onSubmit 콜백을 실행해요. 그리고 errors는 필드 유효성 검사를 도와주죠.
2. useFieldArray - 필드 배열 다루기
DJ: 이제 동적 필드를 다룰 때 유용한 useFieldArray를 살펴봅시다. 전화번호를 추가하거나 삭제해야 할 때 같은 상황에서 유용해요. 같이 코드 예시를 보죠.
import { useForm, useFieldArray } from "react-hook-form";
function PhoneForm() {
const { control, handleSubmit } = useForm({
defaultValues: { phones: [{ number: "" }] }
});
const { fields, append, remove } = useFieldArray({ control, name: "phones" });
const onSubmit = (data) => console.log(data);
return (
<form onSubmit={handleSubmit(onSubmit)}>
{fields.map((field, index) => (
<div key={field.id}>
<input {...register(`phones.${index}.number`)} placeholder="Phone" />
<button type="button" onClick={() => remove(index)}>Remove</button>
</div>
))}
<button type="button" onClick={() => append({ number: "" })}>Add Phone</button>
<button type="submit">Submit</button>
</form>
);
}
DJ: 이 append와 remove 메서드를 이용해 필드를 추가하거나 제거할 수 있어요. 필드 배열 다룰 때 정말 편리하죠?
3. useFormContext - 폼을 여러 컴포넌트에서 공유하기
DJ: 이제 좀 더 복잡한 폼을 다룰 때 유용한 useFormContext를 알아볼게요. 이 메서드는 폼 상태를 여러 컴포넌트에서 공유할 수 있도록 도와줘요. FormProvider와 함께 쓰이죠.
import { useForm, FormProvider, useFormContext } from "react-hook-form";
function FormInput({ name }) {
const { register } = useFormContext();
return <input {...register(name)} />;
}
function ComplexForm() {
const methods = useForm();
const onSubmit = (data) => console.log(data);
return (
<FormProvider {...methods}>
<form onSubmit={methods.handleSubmit(onSubmit)}>
<FormInput name="firstName" />
<FormInput name="lastName" />
<button type="submit">Submit</button>
</form>
</FormProvider>
);
}
DJ: 폼 데이터를 전달할 때는 FormProvider를 써서 상위에서 하위 컴포넌트로 전달해요. 이러면 컴포넌트를 나누면서도 폼 상태를 공유할 수 있죠.
4. Control - Controller와 제어 컴포넌트
DJ: Control은 폼 상태와 메서드를 제어하는 객체로, Controller를 사용할 때 꼭 필요해요. 주로 제어 컴포넌트에서 자주 만나죠.
import { useForm, Controller } from "react-hook-form";
function ControlledForm() {
const { control, handleSubmit } = useForm();
const onSubmit = (data) => console.log(data);
return (
<form onSubmit={handleSubmit(onSubmit)}>
<Controller
name="controlledInput"
control={control}
render={({ field }) => <input {...field} />}
/>
<button type="submit">Submit</button>
</form>
);
}
DJ: Controller를 사용하면 직접 제어 컴포넌트를 다루기 편리해요. render 안에 input을 정의하면서 폼과 연결할 수 있죠.
5. FieldValues - 폼 필드 타입 설정
DJ: 마지막으로 FieldValues를 짚어볼게요. FieldValues는 TypeScript에서 폼 필드의 타입을 설정해줘요. 코드 안정성과 타입 검사를 위해 활용할 수 있죠.
import { useForm, FieldValues, SubmitHandler } from "react-hook-form";
function TypedForm() {
const { register, handleSubmit } = useForm<FieldValues>();
const onSubmit: SubmitHandler<FieldValues> = (data) => console.log(data);
return (
<form onSubmit={handleSubmit(onSubmit)}>
<input {...register("username")} placeholder="Username" />
<button type="submit">Submit</button>
</form>
);
}
DJ: 타입을 지정해 주면서 안정성을 높이고, 폼의 필드에 타입을 명확하게 지정할 수 있어요.
마무리: 오늘 React Hook Form의 주요 메서드를 다루어봤어요! useForm으로 기본 폼을 세팅하고, useFieldArray로 동적 배열을 관리하며, useFormContext로 폼 상태를 공유하고, Control로 제어 컴포넌트를 관리하고, FieldValues로 타입까지 완벽하게 설정할 수 있죠.
여기까지 듣고 나니 이제 조금 폼 작업이 쉬워지겠죠?