react-hook-form 사용하기

LSA·2022년 7월 14일
7

2차 팀 프로젝트

목록 보기
3/3
post-thumbnail

마지막 포스팅 이후로, 취업준비를 하느라 바쁜일의 연속이어서 포스팅이 많이 밀렸네요!
사실 글을 마무리하지 못해서 임시저장된 글만 n개가 쌓여있습니다.
매번 배우는 건 많으면서도, 빠르게 정리하는 것이 힘드네요.

여튼 react-hook-form의 기본 사용법에 이어 실제로 적용한 코드를 되짚어보는 포스팅입니다.
코드 원본은 이 곳에서 확인 가능합니다.

회원가입 페이지

실시간으로 오류를 체크하는 저 폼이 보이실까요?
체크박스를 제외한 input 쪽의 코드만 보겠습니다.

메소드 가지고 오기

import { useForm } from 'react-hook-form';

function Signup() { 
   //validation
    const {
      register,
      handleSubmit,
      watch,
      formState: { errors, isSubmitting, isDirty, isValid },
    } = useForm({ mode: 'onChange' });
  
}

먼저 react-hook-form에서 아래의 메소드들을 가지고 옵니다.

  1. register : 폼들의 유효성을 확인하는 메소드에요.
  2. handleSubmit : 폼을 제출하기 위한 함수에요.
  3. watch : 실시간으로 입력폼에 적힌 값을 확인하는 옵션입니다. (keyUp event가 일어날때마다 e.target.value를 확인하는 기능이라고 보면 되겠네요)
  4. formState : 공식 문서를 직역하자면,

    이 개체는 전체 양식 상태에 대한 정보를 포함합니다. 양식 응용 프로그램과의 사용자 상호 작용을 추적하는 데 도움이 됩니다.

정확한 의미는 모르겠지만, 해당 폼에서 일어난 에러와 제출 여부, 값들이 유효한지 등의 세부적인 상태를 확인할 수 있도록 만들어진 객체 타입인 것 같습니다. isDirty는 어떤 역할을 할까요? 나중에 알아보도록 합니다.

맨 마지막에 useForm({ mode: 'onChange' }); 코드는 react-hook-form에서 다루는 메인 함수임과 동시에 mode를 설정해줄 수 있어요. 안에다가 객체를 하나 넣어준 뒤 mode : 'onChange를 입력하면 실시간 오류 메세지를 출력할 수 있답니다.

데이터를 보내는 함수와 에러

import { useForm } from 'react-hook-form';

function Signup() { 
   //validation
    /*const {
      register,
      handleSubmit,
      watch,
      formState: { errors, isSubmitting, isDirty, isValid },
    } = useForm({ mode: 'onChange' });
  */
  
  const navigate = useNavigate();
  //post
  const onSubmit = data => {
    console.log(data);
    fetch(`http://localhost:8000/user/signup`, {
      method: 'POST',
      headers: { 'Content-type': 'application/json' },
      body: JSON.stringify({
        username: data.username,
        email: data.email,
        password: data.password,
      }),
    })
      .then(res => res.json())
      .then(() => {
        alert(`회원가입 완료! 로그인 후 이용해주세요.`);
        navigate('../login');
      });
  };
	//error
  const onError = errors => console.log(errors);

}

data 인자를 받는 onSubmit 이라는 함수를 만들었어요.
fetch 함수 내에는 회원가입 처리를 할 api의 주소를 넣고, header와 body를 설정해 전달받은 이름/이메일/패스워드를 보냅니다. username,emiail,password라는 키 이름은 백엔드에서 설정된 이름 컨벤션에 따라서 얼마든지 달라질 수 있어요. 일단 저희 팀의 프로젝트에선 저렇게 설정됐습니다!

회원가입이 잘 완료된다면
'회원가입 완료! 로그인 후 이용해주세요.'
라는 alert 창이 뜬 후 로그인 페이지로 이동되어요.
navigate 함수는 react-router-dom의 useNavigate 훅을 사용했습니다.

에러가 날 경우, 에러 핸들링을 하기 위해 onError라는 함수도 만들었어요.
파라미터로 errors를 받아와 어떤 에러가 났는지 콘솔에 출력하도록 합니다.

이름과 이메일 입력하기


function Signup() { 
//validation
//post
//error 위의 코드들이 들어가있다는 가정 하에 

  return (
      <form onSubmit={handleSubmit(onSubmit, onError)}>
  {/*이름 에러 핸들링*/}
        {errors.username && errors.username?.type === 'required' && (
          <AlertMessage>이름을 입력하세요.</AlertMessage>
        )}
        {errors.username && errors.username?.type === 'minLength' && (
          <AlertMessage>{errors.username.message}</AlertMessage>
        )}

        <Input
          type="text"
          placeholder="이름(실명을 입력해주세요.)"
          aria-invalid={errors.username ? '#ff0000' : '#dadada'}
          {...register('username', {
            required: true,
            minLength: { value: 2, message: '이름은 2자 이상이어야 합니다.' },
          })}
        />
 {/*이메일 에러 핸들링*/}
        {errors.email && errors.email?.type === 'required' && (
          <AlertMessage>이메일을 입력하세요.</AlertMessage>
        )}
        {errors.email && errors.email?.type === 'pattern' && (
          <AlertMessage>@를 포함한 주소를 적어주세요.</AlertMessage>
        )}
        <Input
          type="text"
          placeholder="이메일을 입력해주세요."
          aria-invalid={errors.email ? '#ff0000' : '#dadada'}
          {...register('email', {
            required: true,
            pattern: /@/,
          })}
        />

      </form>
  );
}

<form> 태그를 먼저 생성합니다.
그다음 <input> 태그로 텍스트 입력 폼을 만들어요. (여기서는styled-components 라이브러리를 사용하여, 태그의 클래스명을 컴포넌트처럼 만들어서 <Input> 으로 사용합니다.)

그리고 기본 react-hook-form의 사용법을 따라 컴포넌트 태그 안에 {...regitser()} 함수를 사용했어요.
이름을 입력하는 input 의 이름은 username입니다. 그래서 최종적으로 데이터를 넘길때에도 username이라는 키값을 넘겨줍니다.

onSubmit 함수에서 username,email,password 키 값을 넘겨주어야 하기 때문에 이 값들은 필수적으로 입력되어야 합니다! 두 번째 인자로 넘겨받는 객체에 required : ture가 들어가는 이유가 되겠네요.

그리고 이름 입력칸에는 조건이 있습니다!

minLength: { value: 2, message: '이름은 2자 이상이어야 합니다.' }

최소 2자 이상의 문자열을 넣어야 하는데요, 이 조건을 충족하기 위해 required 다음으로 minLength라는 프로퍼티를 추가했어요. (참고)

유효성 검사를 하기 위한 기본적인 속성들이 register의 객체 프로퍼티에 들어가 있습니다. 엄청 편하네요!
value 다음에 들어가는 저 message는 이후 조건을 만족하지 못했을 때의 에러 메시지 출력용으로 넣었습니다.

이메일 input도 마찬가지, 프로퍼티 이름만 바뀐다
이메일 조건은 이름보다 더 단순합니다.(원래는 단순하면 안되지만..)
저희의 경우는 이메일이 @만 들어가면 대충 이메일이다~라고 인식할 수 있게 설정했어요.
그래서 pattern 프로퍼티를 사용하여 유효 조건을 만들어줍니다.

 {...register('email', {
            required: true,
            pattern: /@/,
          })}

pattern에는 정규 표현식을 입력해주면 되는데요, 문자열의 일정한 패턴을 표현하는 형식 언어라고 합니다. 간단히 데이터를 입력하기 위한 조건을 설정하는 식이라고 이해해도 무방할것 같습니다.(무엇이든 사전적인 정의가 제일 설명이 어려운 법이다.)

때문에 /@/라는 내용은 공식 문서를 참조해서 작성한 코드인데,

pattern 값은 기본적으로 /로 시작해서 /로 끝나는 것 같아요.

에러 핸들링 코드 보기

코드를 조금 더 위쪽으로 올라가, 에러 핸들링 코드를 볼게요.

 {/*이름 에러 핸들링*/}
        {errors.username && errors.username?.type === 'required' && (
          <AlertMessage>이름을 입력하세요.</AlertMessage>
        )}
        {errors.username && errors.username?.type === 'minLength' && (
          <AlertMessage>{errors.username.message}</AlertMessage>
        )}

이 부분은 조건부 렌더링문법을 이용하여 작성했어요.
username input의 조건을 만족하고, 필수값이 입력된다면 아무 메시지도 뜨지 않겠지만...
둘 중 하나라도 조건이 충족되지 못하면 input의 테두리 색이 붉어지면서 빨간 오류 메세지도 뜰 예정입니다.
그러기 위해서는 <AlertMessage> 라는 컴포넌트가 필요한데, 이 역시 스타일링 된 컴포넌트입니다. css 단을 살짝 볼까요.

const AlertMessage = styled.span`
  margin-bottom: 5px;
  color: ${props => props.theme.alert};
  font-size: ${props => props.theme.fontSize.small};
`;

간단히 이렇게 스타일이 입혀진 컴포넌트라고 보시면 됩니다.
그럼 input의 테두리 색은 어떻게 바꾸냐?

const Input = styled.input`
  border-color: ${props => props['aria-invalid']};
 `

props로 전달받은 속성 중 aria-invalid 값의 상태에 따라서 border color가 바뀌는 방식입니다.
Input 태그에 있던 수상한 속성이 이곳에 쓰입니다.

 <Input
         
   바로이것 >> aria-invalid={errors.username ? '#ff0000' : '#dadada'}

errors.username의 값이 true라면 aria-invalid 속성은 #ff0000라는 빨간색 값을 가져요.

이러한 2가지의 에러를 핸들링하는 코드를 작성했는데, 사실 이 부분을 조금 더 간결하게 줄일 수는 없나 하는 의문이 들었습니다. 에러를 핸들링하는 레퍼런스가 부족해서 이부분은 확실히 알기 어려운 것 같아요.

여튼 대부분의 에러 핸들링은 이런 식으로 조건부 렌더링을 해주는 것이 전부입니다. 다른 값들도 공통적으로 적용되는 코드에요.

이름과 이메일 입력만 살펴보았는데 스크롤이 길어졌으므로, 패스워드 코드에 대한 것은 다음 포스팅으로 넘어갑니다.
하지만 공통적인 부분을 여기서 전부 써놔서 패스워드 코드는 비교적 단순하게 설명되겠네요!

profile
진짜 간단하게 작성한 TIL 블로그

0개의 댓글