이전에 작성한 form의 단점
- 제어 컴포넌트로 폼을 다루기 위해서는 하나하나 state를 선언해주고 해당 state를 다루기 위한 핸들링 함수를 만들어야 하고 에러를 위한 state, 검증을 위한 함수 등 모든 유효성 검증을 한다면 코드가 더 길어진다.
- 모든 값이 state로 연결되어 있고 하나의 값이 변할 때마다 여러 컴포넌트들에서 많은 리렌더링이 발생하기 때문에 불필요한 렌더링으로서 불필요한 연산으로 생각할 수 있다.
react-hook-form 을 선택한 이유
- 비제어 컴포넌트를 통해 form을 다루기 때문에 기존에 input 태그를 다루기 위해 선언했던 state가 없어지고 컴포넌트가 관리해야 하는 state 수도 적어졌다. 또 이로 인한 컴포넌트의 렌더링 횟수도 최소화할 수 있게 되었다
- state를 최소화함으로서 state로부터 야기되는 버그 최소화 (렌더링 횟수가 최소화 됨으로써 퍼포먼스 최적화에 큰 이점을 준다)
- 직관적인 코드 (직관적으로 폼을 다룸으로써 form 자체를 직점 다룸으로써 개발을 더욱 직관적으로 편리하게 할 수 있다)
변경된 코드
// register.tsx
<form
className=" rounded px-8 pt-6 pb-8 w-full"
onSubmit={handleSubmit(onSubmit)}
>
<div className="text-red-600 text-sm font-semibold mt-2 mb-6">
{error}
</div>
<label className="block text-black font-2xl font-bold mb-3">
닉네임
</label>
<input
className="appearance-none border border-gray-400 w-full py-2 px-1 text-black placeholder:text-sm"
{...register("userName", {
required: "닉네임을 입력해주세요",
pattern: {
value: /^(?=.*[a-z0-9가-힣])[a-z0-9가-힣]{2,8}$/,
message:
"닉네임은 2~8자로 영어 또는 숫자 또는 한글이 조합되어야 합니다.",
},
})}
name="userName"
type="text"
id="userName"
value={userName}
onChange={(event) => setUserName(event.target.value)}
placeholder="닉네임"
onKeyUp={(e) => {
if (e.key === "Enter") {
handleSubmit(onSubmit);
}
}}
autoFocus
/>
<div className="text-red-600 text-sm font-semibold mt-2 mb-6">
{errors?.userName?.message}
</div>
<label className="block text-black font-2xl font-bold mb-3">
로그인에 사용할 아이디를 입력해주세요.
</label>
<input
className="appearance-none border border-gray-400 w-full py-2 px-1 text-black placeholder:text-sm"
{...register("email", {
required: "이메일을 올바르게 입력해주세요",
pattern: {
value:
/^(([^<>()\\[\\].,;:\\s@"]+(\\.[^<>()\\[\\].,;:\\s@"]+)*)|(".+"))@(([^<>()[\\].,;:\\s@"]+\\.)+[^<>()[\\].,;:\\s@"]{2,})$/i,
message: "이메일 형식에 맞게 입력해주세요,",
},
})}
name="email"
type="email"
id="email"
value={email}
onChange={(event) => setEmail(event.target.value)}
placeholder="이메일"
onKeyUp={(e) => {
if (e.key === "Enter") {
handleSubmit(onSubmit);
}
}}
/>
<div className="text-red-600 text-sm font-semibold mt-2 mb-6">
{errors?.email?.message}
</div>
<label className="block text-black font-2xl font-bold mb-3">
로그인에 사용할 비밀번호를 입력해주세요.
</label>
<input
className="appearance-none border border-gray-400 w-full py-2 px-1 text-black placeholder:text-sm"
{...register("password", {
required: "비밀번호를 입력해주세요",
minLength: {
value: 8,
message:
"비밀번호는 영문 대소문자, 숫자를 혼합하여 8~15자로 입력해주세요.",
},
pattern: {
value: /^[A-Za-z0-9]{8,15}$/,
message:
"비밀번호는 영문 대소문자, 숫자를 혼합하여 8~15자로 입력해주세요.",
},
})}
name="password"
type="password"
id="password"
value={password}
onChange={(event) => setPassword(event.target.value)}
placeholder="비밀번호"
onKeyUp={(e) => {
if (e.key === "Enter") {
handleSubmit(onSubmit);
}
}}
/>
<div className="text-red-600 text-sm font-semibold mt-2 mb-6">
{errors?.password?.message}
</div>
<input
className="appearance-none border border-gray-400 w-full py-2 px-1 text-black placeholder:text-sm"
{...register("confirm", {
required: "비밀번호를 입력해주세요",
minLength: {
value: 8,
message:
"비밀번호는 영문 대소문자, 숫자를 혼합하여 8~15자로 입력해주세요.",
},
})}
autoComplete="new-password"
name="confirm"
type="password"
id="confirm"
value={confirm}
onChange={(event) => setConfirm(event.target.value)}
placeholder="비밀번호 확인"
onKeyUp={(e) => {
if (e.key === "Enter") {
handleSubmit(onSubmit);
}
}}
/>
<div className="text-red-600 text-sm font-semibold mt-2 mb-6">
{errors?.confirm?.message}
</div>
<div className="flex items-center justify-center">
<button
className="w-full text-white bg-black font-bold uppercase text-sm px-6 py-3 shadow hover:shadow-lg outline-none focus:outline-none mb-1"
type="submit"
disabled={isRegister}
>
회원가입하기
</button>
</div>
</form>