React Hook Form으로 회원가입, 로그인 구현하기!
2023년 02월 02일
React Hook Form이 무엇이며 왜 사용하는지?
React Hook Form
은 react에서 form을 더 쉽게 사용하기 위해서 만들어졌습니다.
보통 회원가입 form을 하나 만들기 위해서는 이름, 이메일, 비밀번호, 에러 메시지의 상태 값과
해당 상태들의 정합성을 판단하는 함수, 상태 값을 실시간으로 변경해줄 Handler 회원가입
요청 시 필요한 submit 함수 등등 셀 수 없이 많습니다. 다른 정보가 더 필요한 회원가입 로직이면
더 엄청나게 많은 보일러 플레이트가 발생하게 됩니다.
그래서 대단한 분들이 개발하셔서 배포하신 React Hook Form을 사용하는 것이죠....
저는 작은 토이프로젝트를 만들면서 회원가입, 로그인 기능을 구현하였습니다.
잘못된 정보가 들어있을 수도 있으니 그 점은 감안해서 봐주셨으면 감사하겠습니다. ^-^
로그인 기능을 구현하자!!
우선 첫 번쨰로 로그인 기능을 구현하겠습니다. 로그인에서 필요한 상태 값은
이메일, 패스워드 단 두 가지로 간단하게 먼저 React Hook Form 기능을 구현,사용하겠습니다.
그전에 먼저 설치해야겠죠?
npm i react-hook-form
저희는 useForm
훅을 사용해서 구현하겠습니다.
import React, { useRef, useState } from "react";
import { useForm } from "react-hook-form";
interface FormValue {
email: string;
password: string;
}
const LoginForm = (props: any) => {
const {
register,
handleSubmit,
formState: { errors },
getValues,
} = useForm<FormValue>({ mode: "onChange" });
};
export default LoginForm;
useForm이라는 훅을 가져와서 사용할 것입니다. ts이기떄문에 FormValue라는 interface를
만들었고요 로그인만 구현할 것이기 때문에 email, password만을 정의했습니다.
가져오는 객체의 값이 총 4 + 1개인데 하나씩 설명하겠습니다.
-
register : input 요소를 React hook form과 연결해 검증 규칙을 적용할 수 있게 하는 메소드
-
handleSubmit : form을 submit했을 때 실행할 함수.
-
formState : form state에 관한 정보를 담고 있는 객체
-
errors : input 값들의 에러 정보를 가지고 있는 객체
-
getValues : input 값을 가져올 수 있는 함수
그리고 useForm({ mode: "onChange" })
mode라는 것도 있는데
mode를 설정함으로써 해당 모드의 register 안 검증 로직이 동작하는 규칙을 정할 수 있습니다.
-
onChange : input 값이 바뀔 때마다 검증 로직이 동작합니다.
-
onBlur : 포커스 상태를 잃어 버릴떄 동작합니다.
-
onSubmit : 제출 함수가 실행될 때 동작합니다.
-
onTouched : 첫 번째 blur 이벤트에서 동작합니다. 그 후에는 모든 change 이벤트에서 동작합니다.
-
all : blur 및 change 이벤트에서 동작합니다.
이메일 검증 로직을 우선 구현하겠습니다.
return (
// handleSubmit안에 실제로 동작할 함수를 넣음
<form onSubmit={handleSubmit(props.onSubmit)}>
<div>
<label htmlFor="email">이메일</label>
<input
id="email"
type="text"
placeholder="test@email.com"
// input의 기본 config를 작성
{...register("email", {
required: "이메일은 필수 입력입니다.",
pattern: {
value:
/^[0-9a-zA-Z]([-_.]?[0-9a-zA-Z])*@[0-9a-zA-Z]([-_.]?[0-9a-zA-Z])*.[a-zA-Z]{2,3}$/i,
message: "이메일 형식에 맞지 않습니다.",
},
})}
/>
{errors.email && <small role="alert">{errors.email.message}</small>}
</div>
</form>
);
input을 useForm과 연결하기 위해서 register를 사용합니다. 첫 번쨰 인수는 해당 input의
고유 ID입니다. 두 번째로는 옵션을 객체로 설정하는데 required는 필수 입력이며 입력하지 않을시
errors.email(고유 ID).message에 해당 string 값이 들어가게 됩니다.
pattern에는 해당 값 자체를 정규표현 식으로 검사할 수 있습니다.
에러 메시지를 출력하기 위해서 small 태그 안에 에러 메시지를 출력합니다.
비밀번호 검증 로직을 구현하겠습니다.
return (
<div className="form-control__items">
<label htmlFor="password">비밀번호</label>
<input
id="password"
type="password"
placeholder="*******"
{...register("password", {
required: "비밀번호는 필수 입력입니다.",
minLength: {
value: 7,
message: "7자리 이상 비밀번호를 입력하세요.",
},
})}
/>
{errors.password && (
<small role="alert">{errors.password.message}</small>
)}
</div>
)
비밀번호에는 다른 옵션을 추가하겠습니다. minLength라는 옵션으로
최소 길이를 설정 할 수가 있습니다.
우선 이 정도만 하게 된다면 이렇게 로그인 폼을 구현할 수 있습니다.
저는 토이프로젝트에서 구현했기 때문에 CSS 스타일링 등이 되어있습니다.
완성된 로그인 폼
회원가입 기능을 구현하자!!
저는 회원가입을 할 때 2가지의 input을 추가할 것인데요 사용자의 프로필 사진과, 2차 비밀번호 확인입니다.
2차 비밀번호 확인을 하는 이유는 사용자가 첫 번쨰로 입력한 비밀번호 값을 잘못 입력했을떄를 대비함입니다.
또한 이메일 로직을 살짝 수정했는데 실시간으로 db에 해당 이메일이 존재하는지 여부를 판단하기 위함입니다.
우선 비밀번호 확인 로직을 구현하겠습니다.
<div>
<label htmlFor="password">비밀번호 확인</label>
<input
id="password"
type="password"
placeholder="*******"
{...register("passwordConfirm", {
required: "비밀번호는 필수 입력입니다.",
minLength: {
value: 7,
message: "7자리 이상 비밀번호를 사용하세요.",
},
validate: {
check: (val) => {
if (getValues("password") !== val) {
return "비밀번호가 일치하지 않습니다.";
}
},
},
})}
/>
{errors.passwordConfirm && (
<small role="alert">{errors.passwordConfirm.message}</small>
)}
</div>
고유ID값은 passwordConfirm로 설정했습니다. 여기서 보시면 validate라는 옵션이
존재하는데 해당 옵션은 제가 마음대로 커스터마이징이 가능합니다. 저는 check라는 이름을
설정했지만 다른 이름으로 설정하셔도 상관이없습니다. 그리고 함수를 넣게 되는데 첫 인수는
해당 input의 val 값입니다. 여기서 보시면 getValuse함수에 고유 ID를 넣어서 password input의
값을 가져왔습니다. 만약 두 개의 password input 값이 일치하지 않는다면 error가 나타납니다.
두 번쨰로는 프로필 사진입니다. 사실 프로필사진 같은 경우에 useForm기능을 사용하지 않습니다.
<input
{...register("image")}
id="picture"
type="file"
className="hidden"
accept="image/*"
onChange={props.savePreViewFile}
ref={props.imgRef}
/>
<small role="alert">
선택하지 않을 시 기본이미지가 적용됩니다.
</small>
사실 image라는 고유ID를 넣었지만 사용자가 프로필 사진을 설정하지 않게 할 경우 저희 DB에
존재하는 기본 프로필사진으로 대체할 것이기 때문에 검증 로직이 존재하지 않습니다.
props.savePreViewFile함수는 상위 컴포넌트에서 받은 함수로 미리보기 img값을 전달해줍니다
마지막으로 변경된 이메일 로직입니다.
validate: {
check: async (email) => {
return props.checkExistingUser(email);
},
}
validate 옵션 안에 check라는 함수를 만들었는데 props.checkExistingUser은
실제 db에 http요청을 하여서 해당 이메일 사용자가 존재하는지를 판단해주는 검증 로직입니다.
완성된 회원가입 폼
참고 문서
https://react-hook-form.com/get-started