글쓰는쿼카의 PM 여정

[FP] React-hook-form 라이브러리로 회원가입 만들기 (2024. 8. 6.) 본문

개발/[내배캠] Final Project

[FP] React-hook-form 라이브러리로 회원가입 만들기 (2024. 8. 6.)

글쓰는쿼카 joymet33 2024. 8. 6. 23:56

#스파르타코딩클럽 #내일배움캠프(프론트엔드_React) 
학습주제 : Next.js로 최종 프로젝트 만들기

학습내용 :  React-hook-form

학습일 : 2024. 8. 6.


처음으로 혼자서 외부 라이브러리를 접목해봤다.

로그인, 회원가입, 마이페이지(닉네임 변경, 비밀번호 변경) 등 내가 맡은 페이지는 form 형식이 많다.

 

기본적으로 각 입력창의 유효성 검사를 거쳐서 이메일이나 닉네임은 중복확인을 해야 하고

유효성 검사나 중복확인에서 오류가 발견되면 오류메시지로 보여주며,

최종적으로 데이터베이스 테이블에 반영되기까지 일련의 과정을 지나야 한다.

 

useState로 상태를 관리하였는데 한계를 느끼던 중

중간발표 이후 최적화 시기에 맞춰 react-hook-form 라이브러리를 사용해보려 한다.

 

배운 내용 요약

1. 설치

npm install react-hook-form

 

react-hook-form 은 react vite, next.js(typescript)에서 사용이 가능하다.

프로젝트 설치 후 위 코드를 입력하면 끝!

vite로 기본 동작을 테스트하며 어느 정 이해가 된 다음에 next로 적용해봤다.

(vite... 한달 전에 쓴 건데도 어떻게 설치했는지 버벅거렸다...)

 

2. 공식 문서

React Hook Form 공식문서

https://react-hook-form.com/get-started

 

(주로 사용하는 것)

  • useForm 사용
  • onSubmit 형태 주의!
  • register 함수
  • register 옵션들 : required, min, max, minLength, maxLength, parrern, validate
  • handle errors --- 다음 시간에!
  • schema validation --- 다음 시간에!

 

3. 적용하기

(적용 순서)

1) react-hook-form 설치하기

2) 테스트 파일 생성 후 useForm 기본 틀 만들기 - register, formState, handleSubmit

3) return문 만들기 - 회원가입 입력창(4개) : 이메일, 닉네임, 비밀번호, 비밀번호 확인 

4) register type 설정하고 return문에 등록하기

5) register 옵션 등록하기 - 옵션 설정(3~4개) : required, minLength/maxLength, pattern, validate(이건 잠시 보류)

6) 버튼('회원가입 하기') type="submit" 설정하기

 

(전체 코드)

더보기
"use client";

import { errorMonitor } from "events";
import { SubmitHandler, useForm } from "react-hook-form";

type TInputs = {
  email: string;
  nickname?: string;
  password?: string;
  recheckedPassword?: string;
};

function Test() {
  const {
    register,
    handleSubmit,
    watch,
    formState: { errors }
  } = useForm<TInputs>();

  const onSubmit: SubmitHandler<TInputs> = (data) => console.log(data);

  const checkEmailduplication = (email: string) => {
    console.log("잘 찍히나 봅시다");
    return true;
  };

  console.log(errors.nickname);

  return (
    <form
      onSubmit={handleSubmit(onSubmit)}
      className="w-[350px] flex flex-col mx-auto my-auto items-center justify-center gap-2"
    >
      <div className="flex flex-col">
        <label>이메일</label>
        <input
          type="email"
          placeholder="zzan@zzan.com"
          className="auth-input"
          maxLength={30}
          {...register("email", {
            required: "이메일 형식",
            pattern: /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}$/,
            maxLength: 40,
            validate: (email) => checkEmailduplication(email) || "이미 사용 중인 이메일입니다."
          })}
        />
        {errors.email && <span className="text-info-red text-xs">{errors.email.message}</span>}
      </div>

      <div className="flex flex-col">
        <label>닉네임</label>
        <input
          type="nickname"
          placeholder="3자~7자 한글, 영어, 숫자만 가능"
          className="auth-input"
          maxLength={7}
          {...register("nickname", {
            required: "3자~7자 한글, 영어, 숫자만 가능",
            pattern: /^[ㄱ-ㅎ|가-힣|a-z|A-Z|0-9|]+$/,
            minLength: 3,
            maxLength: 7
          })}
        />
        {errors.nickname && <span className="text-info-red text-xs">{errors.nickname.message}</span>}
      </div>

      <div className="flex flex-col">
        <label>비밀번호</label>
        <input
          type="password"
          placeholder="최소 6자~20자, 영문자+숫자+특수문자 조합"
          className="auth-input"
          maxLength={20}
          {...register("password", {
            required: "최소 6자~20자, 영문자+숫자+특수문자 조합",
            pattern: /^(?=.*[a-zA-Z])(?=.*[0-9])(?=.*[!@#$%^&*?_]).{6,20}$/,
            minLength: 6
          })}
        />
        {errors.password && <span className="text-info-red text-xs">{errors.password.message}</span>}
      </div>

      <div className="flex flex-col">
        <label>비밀번호 확인</label>
        <input
          type="password"
          placeholder="최소 6자~20자, 영문자+숫자+특수문자 조합"
          className="auth-input"
          maxLength={20}
          {...register("recheckedPassword", {
            required: "최소 6자~20자, 영문자+숫자+특수문자 조합",
            pattern: /^(?=.*[a-zA-Z])(?=.*[0-9])(?=.*[!@#$%^&*?_]).{6,20}$/,
            minLength: 6
            // validate: (recheckedPassword) => recheckedPassword !== password || "비밀번호와 일치하지 않습니다."
          })}
        />
        {errors.recheckedPassword && <span className="text-info-red text-xs">{errors.recheckedPassword.message}</span>}
      </div>

      <button type="submit">회원가입 하기</button>
    </form>
  );
}

export default Test;