Performance of React Hook Form
Performance is one of the primary reasons why this library was created.
"성능이 곧 react-hook-form을 만든 이유"
내부적으로 성능 최적화를 고려해 설계되었다. 리렌더링을 최소화 해 불필요한 작업을 방지하고, 빠른 사용자 경험을 제공한다.
📌 대규모 폼이나 복잡한 유효성 검사 로직을 가진 폼에서 특히 유용!!
사용하기 쉽고 직관적인 API를 제공한다.
다양한 유효성 검사 규칙과 커스텀 유효성 검사 규칙을 사용해 폼의 요구사항을 쉽게 처리할 수 있다.
const SignUp = ({ login, setLogin, setOpen }: Props) => {
//입력받은 이메일, 패스워드, 닉네임
const [id, setId] = useState<string>("");
const [pw, setPw] = useState<string>("");
const [pwCheck, setPwCheck] = useState<string>("");
const [name, setName] = useState<string>("");
//유효성 검사에 사용
const pwValid = pwCheck !== "" && pw === pwCheck ? true : false;
const isValid = pwValid && emailValidChk(id) && pw.length > 5 && name !== "" ? false : true;
...
return (
...
<form className="space-y-6" onSubmit={signUpNewUser}>
<div>
<label htmlFor="email" className="block text-sm font-medium leading-6 text-gray-900">
Email address{" "}
{emailValidChk(id) ? (
<span>✅</span>
) : (
<span className="text-xs text-red-600"> 이메일 형식이 유효하지 않습니다.</span>
)}
</label>
<div className="mt-2">
<input
id="email"
name="email"
type="email"
required
className="block w-full rounded-md border-0 p-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6"
onChange={(e) => setId(e.target.value)}
placeholder=" example@where2go.com"
/>
</div>
</div>
//비밀번호 input 생략
<div>
<div className="flex items-center justify-between">
<label htmlFor="pwConfirm" className="block text-sm font-medium leading-6 text-gray-900">
Password 확인{" "}
{!pwValid ? (
<span className="text-xs text-red-600">비밀번호가 일치하지 않습니다.</span>
) : (
<span>✅</span>
)}
</label>
</div>
<div className="mt-2">
<input
id="pwConfirm"
name="pwConfirm"
type="password"
required
className="block w-full rounded-md border-0 p-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6"
onChange={(e) => setPwCheck(e.target.value)}
placeholder=" 비밀번호 재입력"
/>
</div>
</div>
// username 입력 생략
<div>
<Button type="submit" size="md" disabled={isValid} className="sm:mx-auto sm:w-full sm:max-w-sm mb-8 mt-2">
SignUp & Login
</Button>
</div>
</form>
...
);
react-hook-form 없이 만든 회원가입은 input마다 useState로 처리하고, 유효성 검사도 로직을 각각 만들어 에러 메세지 처리를 해야한다. onChange로 state를 변경할 때마다 렌더링 되므로 불필요한 렌더링이 너무 많고, 유효성 검사가 복잡하다는 단점이 한눈에 보인다.
npm install react-hook-form
...
import { useForm, SubmitHandler } from "react-hook-form";
...
interface FormValue {
id: string;
pw: string;
pwCheck: string;
name: string;
}
const SignUp = ({ mode, setMode }: Props) => {
//회원가입 함수 signUpNewUser() 생략
const {
register,
handleSubmit,
watch,
formState: { errors },
setError
} = useForm<FormValue>({ mode: "onBlur" });
//비밀번호 유효성 검사를 위해 pw 입력값 확인
const passwordRef = useRef<string | null>(null);
passwordRef.current = watch("pw");
const onSubmit: SubmitHandler<FormValue> = (inputData) => {
console.log(inputData);
signUpNewUser(inputData.id, inputData.pw, inputData.name);
};
return (
<>
...
<form onSubmit={handleSubmit(onSubmit)} className="space-y-6">
<div>
<label htmlFor="email" className="block text-sm font-medium leading-6 text-gray-900">
Email address
<span className="text-xs text-red-600">{errors?.id?.message}</span>
</label>
<div>
<input
id="email"
type="email"
{...register("id", {
required: " 이메일을 입력하세요.",
pattern: {
value: /^[A-Za-z0-9_\.\-]+@[A-Za-z0-9\-]+\.[A-za-z0-9\-]+/,
message: " 이메일 형식이 유효하지 않습니다."
}
})}
placeholder="example@yolocean.com"
className="block w-full rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-blue-300 sm:text-sm sm:leading-6"
/>
</div>
</div>
<div>
<div className="flex items-center justify-between">
<label htmlFor="password" className="block text-sm font-medium leading-6 text-gray-900">
Password
<span className="text-xs text-red-600">{errors?.pw?.message}</span>
</label>
</div>
<div>
<input
id="password"
type="password"
{...register("pw", {
required: " 비밀번호를 입력하세요.",
minLength: {
value: 6,
message: " 6자리 이상 입력하세요."
}
})}
placeholder="비밀번호를 입력하세요."
className="block w-full rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-blue-300 sm:text-sm sm:leading-6"
/>
</div>
</div>
<div>
<div>
<label htmlFor="pwConfirm" className="block text-sm font-medium leading-6 text-gray-900">
Password 확인 <span className="text-xs text-red-600">{errors?.pwCheck?.message}</span>
</label>
</div>
<div>
<input
id="pwConfirm"
type="password"
{...register("pwCheck", {
required: true,
validate: (value) => (value === passwordRef.current ? true : " 비밀번호가 일치하지 않습니다.")
})}
placeholder="비밀번호 확인"
className="block w-full rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-blue-300 sm:text-sm sm:leading-6"
/>
</div>
</div>
<div>
<div>
<label htmlFor="name" className="block text-sm font-medium leading-6 text-gray-900">
Username
<span className="text-xs text-red-600">{errors?.name?.message}</span>
</label>
</div>
<div>
<input
id="name"
type="name"
placeholder="yolocean에서 사용할 이름을 입력하세요"
{...register("name", {
required: " 이름을 입력하세요"
})}
className="block w-full rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-blue-300 sm:text-sm sm:leading-6"
/>
</div>
</div>
<div>
<button
type="submit"
// disabled={isValid}
className="flex w-full justify-center rounded-md bg-blue-600 px-3 py-1.5 text-sm font-semibold leading-6 text-white shadow-sm hover:bg-blue-700 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-blue-600 cursor-pointer"
>
SignUp & Login
</button>
</div>
</form>
<div>
<p
onClick={() => setMode(!mode)}
className="mt-10 text-center text-sm text-blue-700 hover:text-blue-500 cursor-pointer"
>
로그인 하기
</p>
</div>
</div>
</div>
</>
);
};
...
<input id="email" type="email" {...register("id", { required: " 이메일을 입력하세요.", pattern: { value: /^[A-Za-z0-9_\.\-]+@[A-Za-z0-9\-]+\.[A-za-z0-9\-]+/, message: " 이메일 형식이 유효하지 않습니다." } })} placeholder="example@yolocean.com" className="..." />
- 첫번째 매개변수 name : 해당 필드를 다룰 key값으로 반드시 들어가야 하는 값이다.
- 두번째 매개변수 options 객체: 유효성 검사를 위한 프로퍼티들이 들어갈 수 있다.
- required, min, max, minLength, maxLength, pattern 등...
- value와 message로 구성된 객체를 주면 해당 에러에 대한 구체적인 메세지를 제공할 수도 있다.
//비밀번호 유효성 검사를 위해 pw 입력값 확인
const passwordRef = useRef<string | null>(null);
passwordRef.current = watch("pw");
폼에서 데이터를 입력하고 사용자가 등록(회원가입) 버튼을 누르면 submit 이벤트가 발생한다. 이때, 사용자가 해당 데이터를 올바른 형식으로 입력했는지 검증을 한다. form 태그의 onSubmit 에 handleSubmit 이라는 함수를 넣어주고 매개변수로 우리가 정의한 onSubmit 함수를 넣어주면 된다. onSubmit 함수를 정의 할 때 매개변수로 data 라는 값을 받을 수 있는데, 해당 값은 사용자가 제출 버튼을 클릭 한 후 내려오는 사용자 입장에서 최종으로 제출하는 데이터가 된다. 이 값을 이용해 서버에 값을 넘겨주면 된다.