React-Hook-Form과 zod를 사용하여 효율적으로 폼 관리하기

dongmin·2024년 4월 17일
26
post-thumbnail

개요

현재 진행 중인 프로젝트에서 로그인 기능이 필요하여 로그인 및 회원가입에 대한 폼을 제작해야 했다. 다음은 기존에 입력 폼을 만들던 방식의 예제 코드이다.

function MyForm(){
  
  const [email,setEmail] = useState<string>('');
  
  const handleEmail = (event) => {
    setEmail(event.target.value);
  };
  
  return
  	(
	<input 
      type="email"
      placeholder="이메일을 입력하세요"
      value={email} 
      onChange={handleEmail}/>
    )
}

입력 창에 값이 입력될 때마다 값을 추적하고 setEmail 함수를 호출하여 email 값을 업데이트한다. 문자 1개를 입력할 때마다 setEmail 함수가 실행되는 것이다.

-> 사용자의 입력값이 실시간으로 동기화되는 제어 컴포넌트 로써 동작한다.

문제

React-Hook-Form의 필요성

React 에서는 state 값이 변경될 때마다 페이지를 다시 렌더링한다.

이러한 이유로 위의 예제 코드의 방식대로 입력을 받게 되면 매우 많은 리렌더링이 발생하게 되어 불필요한 렌더링을 요구하는 코드이다.

불필요한 렌더링은 성능저하를 초래하는 원인이 될 수 있기에 불필요한 렌더링을 없애야 한다고 생각했다.

React-Hook-Form 라이브러리를 사용하여 비제어 컴포넌트 로써 불필요한 렌더링을 제거할 수 있고 상황에 맞게
제어 컴포넌트 도 사용할 수 있어 비제어 컴포넌트제어 컴포넌트 의 장점을 모두 챙길 수 있다.

제어 컴포넌트와 비제어 컴포넌트의 차이

  • 제어 컴포넌트 - 실시간으로 입력값 동기화 -> 입력값에 대한 실시간 피드백 가능
  • 비제어 컴포넌트 - 실시간으로 입력값이 동기화되지 않음 -> 불필요한 렌더링 제거

zod의 필요성

회원가입 폼을 만들기 위해서 특정 규칙에 맞는 입력 값인지 검사를 해야 한다.
이런 유효성 검사에 관한 내용을 폼 내부에 작성하게 되면 코드의 가독성이 떨어진다.

zod 를 사용하면 폼과 유효성 검사를 위한 코드에 관한 내용을 분리하여 작성할 수 있다.

해결

프로젝트에 React-Hook-Form, zod 설치

npm install react-hook-form zod @hookform/resolvers    	// npm
yarn add react-hook-form zod @hookform/resolvers 		// yarn

zod를 이용하여 Schema 작성

const signUpFormSchema = z
    .object({
      // 이메일 형식 지정
      email: z.string().email({ message: '이메일 형식이 아닙니다.' }), 
      password: z // 비밀번호 형식 지정 (문자와 숫자가 혼합된 8~20자리)
        .string()
        .regex(
          /^(?=.*[a-zA-Z])(?=.*[0-9]).{8,20}$/,
          '문자와 숫자가 혼합된 8~20자리의 비밀번호를 입력해주세요.'
        ),
      confirmPassword: z.string(),
      nickname: z.string(),
      name: z.string(),
    })
    // 비밀번호와 비밀번호 확인이 일치하는지 확인
    .refine((data) => data.password === data.confirmPassword, {
      path: ['confirmPassword'],
      message: '비밀번호가 일치하지 않습니다.',
    });

회원 가입을 하기 위해서 입력받을 각 값의 규칙과 해당 규칙에 맞지 않을 때 출력할 메시지를 정의한다.

  • email : 이메일 형식
  • password : 문자와 숫자가 최소 1개씩 혼합된 8~20자리
  • confirmPassword : password 의 값과 같아야 함
  • nickname , name : 문자열

useForm

// useForm을 사용하여 회원가입 폼의 상태 관리
  const form = useForm({
    resolver: zodResolver(signUpFormSchema),
    defaultValues,
    mode: 'onSubmit',
  });

  const {
      register,
      formState: { errors },
    } = form;
  • resolver : signUpFormSchema 를 전달하면 내가 작성한 규칙대로 form 에서 유효성 검사를 한다.

  • defaultValues : 초깃값을 설정한다.

  • mode : form 의 유효성 검사를 언제 할지 설정한다.

    React-Hook-Form 라이브러리의 useForm 훅을 사용하여 mode를 onSubmit 으로 설정해줌으로써 비제어 컴포넌트 가 되어 불필요한 렌더링을 제거한 것이다.
    만약, mode를 onChange로 설정한다면 입력값에 실시간으로 피드백이 가능한 제어 컴포넌트 로써 동작할 것이다.

  • register : 입력 필드를 React Hook Form에 등록하여 제어하고, 유효성을 검사한다.

  • formState : 입력 필드의 상태를 return 한다.

입력 필드에 유효성 검사 적용

<FormProvider {...form}>
	<TextField
            {...register('email')}
            {errors.email ? errors.email.message : '사용가능한 이메일입니다.'}
          />
</FormProvider>
  • {...register('email')} : 입력 필드를 등록하고 스키마에서 email 에 설정한 규칙을 기반으로 유효성 검사를 한다.

  • {errors.email ? errors.email.message : '사용가능한 이메일입니다.'} : 규칙에 맞지 않는 입력 값이라면 스키마에서 설정했던 메시지가 출력된다.

    zod를 사용하여 유효성 검사에 대한 로직을 분리해서 작성하여 가독성 좋은 입력 필드를 구현했다.

결론

React-Hook-Form 을 사용하여 폼의 상태를 관리하여 불필요한 렌더링을 방지함으로써 성능을 개선하였고,
zod 를 사용하여 유효성 검사를 함으로써 코드의 가독성을 향상시켰다.

📕 Reference

profile
아이스박스

4개의 댓글

comment-user-thumbnail
2024년 4월 18일

좋은 글 감사합니다!

답글 달기
comment-user-thumbnail
2024년 4월 19일

유익한 글 감사합니다~ 잘 읽고가요!

답글 달기
comment-user-thumbnail
2024년 5월 7일

좋은 글 읽고 갑니다!

답글 달기
comment-user-thumbnail
2024년 5월 10일

잘 읽고 갑니다^!^

답글 달기