react-hook-form 리액트 유효성 검사
작업중인 웹페이지에 회원가입 탭이다. 내 쿼리에 들어갈 정보들 중, 자동입력되는 값들을 제외하고 모두 입력받는 폼이다. 우리는 이 정보들이 제대로 들어오게, 쿼리에서 오류를 반환하지 않도록 해야하는 의무가 있다.
그러기위해 보통 유효성검사를 사용한다. 서버쪽 코드에서도 사용할 수 있지만, 보통 클라이언트단에서 처리하기 때문에, 우리는 리액트에서 유효성 검사를 어떻게 하는지 알아보자
React Hook Form
React Hook Form은 React 기반의 라이브러리로, 유효성 검사, 폼 제출을 쉽게 처리할 수 있도록 도와주는 라이브러리다. 직관적인 api가 제공되고, 비슷한 기능을 제공하는 Formik 보다 안정적인 성능을 지원한다.
- Hook 기반으로 폼 상태와 동작을 관리, 'useForm' 을 사용해 인스턴스를 생성 - 다양한 훅을 사용
- Form-uncontrolled 컴포넌트를 사용하여 form 값 추적, ref를 사용해 필드를 연결, 추적, 검사 작업 수행
- HandleSubmit 함수를 사용하여 폼의 제출 처리, 제출 이벤트를 핸들링 가능
React Hook Form 설치
npm install react-hook-form
react-hook-form 라이브러리를 설치
React Hook Form 적용
라이브러리를 사용할 form이 존재하는 페이지에 해당 라이브러를 import 해준다.
import { useForm } from "react-hook-form";
그 후, useForm에 존재하는 hook을 호출해야한다. 메인 컴포넌트 함수 내에서 아래와 같은 useForm 훅을 호출하자
const { handleSubmit, register, formState: { errors } } = useForm();
const onSubmit = (data) => {
console.log(data); // 폼 데이터를 처리하는 로직을 작성합니다.
};
폼을 제출하는 이벤트가 발생할 경우, 실행될 핸들러 함수 실제로 데이터를 처리하는 로직은 이곳에 작성해야한다. 지금은 서비스 로직을 따로 구현하지 않기때문에 유효성체크가 되지 않으면 알람이 뜨는 정도만 진행한다.
<form onSubmit={handleSubmit(onSubmit)}>
<input
type="text"
name="username"
placeholder="사용자 이름"
{...register("username", { required: true })}
/>
{errors.username && <span>사용자 이름은 필수입니다.</span>}
{/* ... */}
<button type="submit">제출</button>
</form>
폼을 제출하기 위한 form을 선언하고, onSubmit (위에서 선언한 핸들러 함수)를 handleSubmit(onSubmit)을 사용하여 태그에 추가하자
그 후 중요한건 name="" 과 {...register에 등록될 프로퍼티의 이름이 동일해야 한다. 해당 프로퍼티 값을 통해 유효성을 체크한다.
<Form.Control
type="text"
placeholder="이메일"
name="email"
{...register("email", {
required: true,
pattern: /^\S+@\S+$/i
})}
/>
이처럼 정규식을 사용하거나, 유효성 검사 규칙을 설정할 수 있기때문에 기본적인 사항은 모두 적용 가능하다.
register("name", {required: true, minLength: 10});
register("name", {required: "해당 필드는 필수입니다.", minLength: {
value: 3,
message: "3글자 이상 입력해주세요."
}
});
위와 같은 사양도 가능하다. 생각보다 바리에이션이 많으니 공식문서를 참고하는게 좋다.
React Hook Form - performant, flexible and extensible form library
Performant, flexible and extensible forms with easy-to-use validation.
react-hook-form.com
register 함수에는 프로퍼티 값이 들어간다, 에러 정보를 입력하는건 errors 함수에 들어간다. errors는 formState에 객체에 존재한다. 해당 객체에 { id : { type: ..., message: ..., ... } 로 저장된다. formState는 단어 그대로 해당 폼에 정보에 대한 값들이 들어있다.
submit 된 숫자, 혹은 수정된 필드들이 담겨있는 dirtyFields, 에러가 있는지 알 수 있는 isValid 등등이 존재한다.
watch / getValues
위 함수는 둘다 값을 추적하는 함수로, 비밀번호 확인이나 동일값을 비교할때 자주 사용된다.
<Form.Control
type="password"
placeholder="비밀번호"
name="password"
{...register("password", {
required: true,
minLength: 6
})}
/>
{errors.password && errors.password.type === "required" && (
<ErrorMessage>비밀번호는 필수 입력 항목입니다.</ErrorMessage>
)}
{errors.password && errors.password.type === "minLength" && (
<ErrorMessage>비밀번호는 최소 6자 이상이어야 합니다.</ErrorMessage>
)}
<Form.Control
type="password"
placeholder="비밀번호 확인"
name="confirmPassword"
{...register("confirmPassword", {
required: true,
validate: (value) =>
value === getValues("password") || "비밀번호가 일치하지 않습니다."
})}
/>
{errors.confirmPassword && errors.confirmPassword.type === "required" && (
<ErrorMessage>비밀번호 확인은 필수 입력항목입니다.</ErrorMessage>
)}
{errors.confirmPassword && errors.confirmPassword.type === "validate" && (
<ErrorMessage>{errors.confirmPassword.message}</ErrorMessage>
)}
watch("name값")
비제어 컴포넌트로 폼을 구현할 때에 조건에 따라, 다르게 필드를 노출해야 하는 상황이 존재한다. 이런 상황에서 watch 함수는 폼에 입력된 값을 구독하여 실시간으로 체크할 수 있다. 매개변수를 주지 않으면 전체 값, 매개변수를 받는다면 해당 값만 관찰한다.
getValues("name값")
두개의 또렷한 차이점은 getValues같은 경우는 컴포넌트의 리렌더링을 일으키지 않는다. 입력값의 변화를 구독하지 않는다는 점도 존재한다.