시도하게 된 이유
내가 만들고 있는 회원가입 페이지에는 꽤 많은 입력 필드가 있다.
여기에 판매자 회원가입 필드까지 하면 관리해야 하는 필드가 두배로 늘어난다.
뭐 이정도는 대부분의 사이트에서 받고 있는 유저정보이니까 절대 과하지는 않다. 아니 실제 서비스되는 페이지는 여기에 뭐 주소나 별명같은것까지 더 입력해야 하지 않은가? 그래서 이정도 관리하는건 별거 아니라고 생각했다.
근데 막상 이걸 일일이 useState로 관리하는 것은 생각보다 번거로운 일이었다ㅠ
각 항목마다 유효성 검사를 해야하니까 그에대한 state도 늘어날 뿐더러 나는 아토믹패턴으로 프로젝트를 만들고 있기 때문에 모든 인풋창이 각기 다른 컴포넌트에 있어서 props로 state를 일일이 보내주는 식으로 관리해야 했다.
대충 봐도 이건 아니다 싶었다,,
세상 지저분한 코드가 되었다. 그래서 각 state를 리덕스에다 저장할까도 생각해봤는데 가입할 때 잠깐 쓰는 건데 그걸 넣어놓는게 좀 비효율적인 거 같고 보안 문제도 있을 것 같고(내생각이라서 아닐수도 있음), 찾아보니 보통 그렇게 하지는 않는 것 같았다.
좋은 방법이 없을까 싶어서 찾아보던 와중 React Hook Form이라는 좋은 리액트훅을 발견했다.
이걸 쓰면 제출하는 데이터도 따로 state를 관리할 필요 없이 한번에 모아서 api에 보낼수 있고, 유효성 검사도 간편하고, 잘못된 형식으로는 제출이 안되도록 막을 수도 있었다. 진작 알았으면 좋았을걸!
https://www.daleseo.com/react-hook-form/ 이 글에서 알기 쉽게 설명을 해주셔서 많이 도움이 되었다ㅠㅠ
사용방법
일단 얘는 npm으로 쉽게 다운받을 수 있다. 터미널에 이걸 입력해주고 설치했다.
npm install react-hook-form
그리고 다른 리액트훅을 사용할 때와 똑같은 방법으로 useForm를 컴포넌트에서 불러올 수 있다.
import {useForm} from 'react-hook-form'
useForm은 register() 와 handleSubmit() 이라는 두개의 함수를 제공한다.
register함수는 입력폼의 항목을 등록할 수 있고 handleSubmit은 입력한 데이터들을 모아서 하나의 객체로 만들어준다.
const {register, handleSubmit} = useForm();
예를 들어서 입력해서 객체로 만들어주고 싶은 값이 id 라면 id의 인풋에 register 함수를 사용해서 등록하면 된다.
나는 id의 인풋이 하위 컴포넌트에 있기 때문에 register를 내려보내주어서 등록했다. 나는 컴포넌트가 세분화되어있어서 각 인풋마다 register를 보내주는게 불가피할 것 같다.
register로 등록할 때는 첫번째 인자에 등록할 항목 이름을 적고, 두번째 인자에 유효성 검증을 위한 설정값들을 적으면 된다. required, pattern, minLength 같은 것들을 적을 수 있다고 한다. 나는 첫번째 인자를 id로 하고 두번째 인자에는 required만 적었다.
그리고 폼이 제출되었을 때 handleSubmit 함수를 실행하도록 하였는데 만들어진 객체를 출력할 수 있도록 일단 콘솔을 찍어봤다.
요렇게 잘 출력되었다. 신기함!!
이어서 다른 것들도 다 등록해보기로 했다.
참고로 나는 register를 모든 인풋 컴포넌트에서 props로 받고 있기 때문에 계속 props.register로 써주고 있다.
비밀번호 입력창에는 required, minLength, pattern 속성을 사용해서 유효성 검사를 해줬다.
각 검사에 해당하는 value값도 써줬고 통과하지 못했을 시에 나타나는 에러메세지도 설정할 수 있다. 참고한 글을 보면 이렇게 객체 형식으로 작성하는 것 같다.
이메일 입력창도 등록해주고 유효성 검사를 작성해주었다. 여러번 하니까 별로 어렵지 않다ㅎㅎ 이메일 인풋은 @을 기준으로 앞뒤 두개이기 때문에 등록 이름을 emailFirst , emailSecond로 지었다. 이후에 서버에 회원가입 요청을 보낼 때는 각 값을 합쳐서 보내야할 것 같다.
이제 나머지 값도 모두 register 해준 다음에 이렇게 모든 입력 필드에 값을 채우고 가입하기를 누르면 제출된다.
나는 콘솔창에 제출된 값들이 나타나도록 객체를 출력해주었다. 이렇게 잘 나타난다!
만약 required로 설정해둔 값을 하나라도 빼먹고 가입하기 버튼을 누르면 빼먹은 필드에 focus가 되면서 제출이 되지 않는다.
어쨌든 이제 제출이 되고 나면 form의 중복제출을 막기 위해서 한가지 더 해줘야할게 남았다. useForm에서 isSubmitting이라는 속성이 있는데 이것은 form이 제출중인지 아닌지를 반환한다. 이 속성을 사용하기 위해서 useForm에서 formState라는 속성을 추가로 가져와주었다.
const {
register,
handleSubmit,
formState: { isSubmitting }
} = useForm();
isSubmitting은 bool 값을 반환한다. 제출하기 전에는 false였다가 제출하기를 누르는 순간 true로 바뀐다. 그래서 이 값에 따라서 가입하기 버튼을 조절했다. 이렇게 disabled 속성을 두면 제출하는 도중에 버튼을 사용할수 없게 될것이다.
근데 제출하는 속도가 너무 빠르다보니 감지하기가 어려워서 1초의 시간 간격을 두었다. 그리고 나서 콘솔창에 찍힌 것을 보면 내가 제출하기 버튼을 연타하였는데도 제출이 한번밖에 안된다.
시간 간격을 두지 않으면 위 사진과 같이 버튼을 연타하면 제출이 계속 된다.
시간 간격을 두면 버튼을 1초 안에 연타하면 제출이 한번밖에 안된다는 것을 확인할 수 있다.
사용후기
이렇게 useForm을 사용해봤는데 처음부터 이걸 썼으면 훨씬 작업이 빨랐을 것 같다. 유효성 검사나 제출 감지 등이 간편하고 정확하게 되다보니 너무 편한 것 같다.
그리고 나처럼 아토믹패턴으로 개발하려는 사람에게는 더더욱 좋다. 모든 state들을 여러 컴포넌트에서 관리하는 것은 어려운 일이다.
다만 아직 에러메세지가 나타나게 하는 것을 못했는데 글이 너무 길어지는 것 같아서 다음 편에서 계속 쓸 예정이다.
'Frontend' 카테고리의 다른 글
Atomic Design Pattern 사용기 (0) | 2024.01.05 |
---|---|
react-hook-form 에서 useFormContext 사용하기 (react form에서 props driiling을 막아보자) (0) | 2023.09.06 |
리액트 회원가입 시 유저 비밀번호 일치여부 검증 오류 (0) | 2023.08.25 |
리액트에서 동적인 UI 만드는 방법 (2) | 2022.12.04 |
자바스크립트 이벤트 실행 후 페이지가 reload 되는 현상: button에 type 지정해라.. (0) | 2022.11.05 |