프로젝트를 구현할 때에는 서버로 사용자가 입력한 정보를 보내주는 기능이 필요합니다. 회원가입이나 파일 전송 등 다양한 기능에서 사용되는데요. 이 글에서는 React-Hook-Form 라이브러리를 소개하고 설명합니다.
제어 컴포넌트는 컴포넌트의 상태를 React에서 관리하기 때문에, 컴포넌트의 상태가 변경될 때마다 리렌더링이 발생합니다. 반면, 비제어 컴포넌트는 컴포넌트의 상태를 State에서 관리하지 않고 DOM으로 바로 접근(ref)하기 때문에 이벤트가 발생해도 화면의 리렌더링이 일어나지 않습니다.
import { useState } from 'react';
const Form = () => {
const [name, setName] = useState('');
const [isError, setIsError] = useState(false)
const handleSubmit = e => {
e.preventDefault();
if(name === '') return setIsError(true)
alert('API Request')
};
const onChangeNameHandler = e => {
e.preventDefault();
console.log('NAME:', name);
};
return(
<form onSubmit={handleSubmit}>
<input
type="text"
placeholder="Name"
value={name}
onChange={onChangeNameHandler}
/>
<button>Enter Name</button>
{isError && '이름을 빈 값으로 제출할 수 없습니다.'}
</form>
);
};
export default Form;
React에서는 일반적으로 제어 컴포넌트를 사용할 것을 권장하지만, 값이 바뀔 때마다 렌더링을 하기 때문에 불필요한 리렌더링 혹은 API 요청이 발생하기도 합니다. 때문에 폼의 Input 값을 onChange로 감시할 경우, Input이 많아지면 많아질수록 성능 이슈가 발생할 수 있습니다.
React Hook Form은 React에서 폼을 만들 때 유용한 라이브러리입니다. React Hook Form은 비제어 컴포넌트를 활용하여 불필요한 리렌더링을 방지하여 직접 구현할 때보다 성능상 이점이 있고, 실시간 유효성 검사 등 다양한 기능을 제공합니다. 뿐만 아니라 가장 많은 사람들이 채택하고 있는 폼 라이브러리로 유저 풀이 넓으며 지속적으로 유지 보수가 이루어지고 있습니다. 타입스크립트를 기본으로 지원합니다.
npm install react-hook-form
import { useForm, SubmitHandler } from "react-hook-form"
type Inputs = {
example: string,
exampleRequired: string
}
export default function App() {
const {
register,
handleSubmit,
watch,
formState: { errors },
} = useForm<Inputs>()
// onSubmit 이벤트에서 트리거되는 handleSubmit함수의 인자 data에는 register 함수로 등록된 모든 값이 들어옵니다.
const onSubmit: SubmitHandler<Inputs> = (data) => console.log(data)
console.log(watch("example")) // input의 값 변화를 감지하여 값 출력
return (
/* "handleSubmit" 함수는 submit 이벤트가 발생하면 입력 필드의 값을 유효성을 검사한 후 "onSubmit" 함수를 호출합니다.*/
<form onSubmit={handleSubmit(onSubmit)}>
{/* "register" 함수를 사용하여 입력 필드를 hook에 등록합니다 */}
<input {...register("example")} />
{/* "register" 함수 내에서 유효성 검사를 할 수 있습니다. */}
<input {...register("exampleRequired", { required: true })} />
{/* rules이 어긋나면 error 정보가 errors 객체에 저장됩니다 */}
{errors.exampleRequired && <span>이 필드는 필수 입력입니다</span>}
<input type="submit" />
</form>
)
}
const { register, handleSubmit, errors } = useForm({
mode: 'onSubmit' // or 'onChange', 'onBlur', 'onTouched'
});
<input {...register('example')} />
watch('example')
getValues('example')
// 버튼을 클릭하면 handleSubmit의 매개변수를 콜백으로 실행합니다.
const submitFunction = (data) => {
// 유효성 검사...
// API 요청...
}
<form onSubmit={handleSubmit(submitFunction)}>
...
<button type="submit">Send</button>
</form>
setValue('message', 'default value')
errors.firstName && <span>{errors.firstName.message}</span>
import { useForm } from 'react-hook-form';
function Form() {
const { register, handleSubmit, setErrors } = useForm();
const onSubmit = (data) => {
// 입력된 값을 가지고 비밀번호와 비밀번호 확인이 일치하는지 확인합니다
if (data.password !== data.confirmPassword) {
setErrors({ confirmPassword: 'Passwords do not match' });
return;
}
console.log(data);
};
return (
<form onSubmit={handleSubmit(onSubmit)}>
{/* 비밀번호와 비밀번호 확인의 유효성 검증 : true */}
<input name="password" type="password" ref={register({ required: true })} />
<input name="confirmPassword" type="password" ref={register({ required: true })} />
<button type="submit">Submit</button>
</form>
);
}
이 외에도 React Hook Form은 수많은 기능을 지원합니다. 해당 페이지에서 확인해보세요!
https://react-hook-form.com/docs/useform
Form 을 통해서 사용자에게 데이터를 입력받는다면 입력받은 데이터를 폼 전송 전에 검증해야 할 필요가 있습니다. React Hook Form의 가장 큰 매력점으로 유효성 검사를 위한 다양한 프로퍼티를 지원해준다는 것을 꼽고 싶습니다. 커스텀 오류가 필요하지 않은 경우 setError
가 아니라 form 태그 안에서 검증을 할 수 있습니다.
import { useForm } from 'react-hook-form';
function MyForm() {
const { register, handleSubmit, errors } = useForm();
const onSubmit = (data) => {
console.log(data);
};
return (
<form onSubmit={handleSubmit(onSubmit)}>
<input
name="name"
ref={register({ required: 'This field is required' })}
/>
{errors.firstName && <span>{errors.name.message}</span>}
<input
name="age"
type="number"
ref={register({
min: { value: 18, message: 'Must be at least 18 years old' },
max: { value: 100, message: 'Cannot exceed 100' }
})}
/>
{errors.age && <span>{errors.age.message}</span>}
<input
name="password"
type="password"
ref={register({ minLength: { value: 6, message: 'Password must be at least 6 characters long' } })}
/>
{errors.password && <span>{errors.password.message}</span>}
<input
name="email"
ref={register({
required: 'Email is required',
pattern: {
value: /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i,
message: 'Invalid email address'
}
})}
/>
{errors.email && <span>{errors.email.message}</span>}
<input
name="username"
ref={register({ validate: value => value === 'admin' || 'Invalid username' })}
/>
{errors.username && <span>{errors.username.message}</span>}
<button type="submit">Submit</button>
</form>
);
}
useForm
을 사용하는 경우에는 반드시 defaultValue
를 넣어줘야 useForm
을 통해 관리되는 필드들의 초기값이 undefined
로 관리되지 않습니다.
Refercnce
⓵ React Hook Form (Official Document) https://react-hook-form.com/
⓶ React controlled vs. uncontrolled components
https://velog.io/@kskim625/React-controlled-vs.-uncontrolled-components
⓷ React 제어 컴포넌트 vs 비제어 컴포넌트
https://itprogramming119.tistory.com/entry/React-제어-컴포넌트-VS-비제어-컴포넌트
⓸ react-hook-form을 이용해 효과적으로 폼 관리하기
https://tech.osci.kr/introduce-react-hook-form/
⓹ 깔끔한 폼 개발과 정시퇴근을 위하여 react-hook-form
https://dealicious-inc.github.io/2022/07/25/ss-studio.html
⓺ React Hook Form을 활용한 회원가입 Validation 구현
https://velog.io/@sweetpumpkin/React-hook-form을-이용한-Form-Validation