Performant, flexible and extensible forms with easy-to-use validation.
유효성 검사를 쉽게 할 수 있는, 성능이 우수하고 유연하며 확장 가능한 form을 제공하는 라이브러리이다.
참고 링크
https://github.com/react-hook-form/performance-compare
소스 코드가 깔끔하다.
: 코드 길이가 다른 라이브러리보다 짧아 syntax가 깔끔하고, 리액트 본연의 syntax와 비슷하여 사용하기 편리하다.
비제어 컴포넌트 방식의 사용으로 불필요한 렌더링을 막아주어 속도가 빠르다.
-> 여기서 리액트의 제어 컴포넌트와 비제어 컴포넌트에 대해 알아야 할 필요가 있다.
HTML에서 <input>
, <textarea>
, <select>
와 같은 폼 엘리먼트는 일반적으로 사용자의 입력을 기반으로 자신의 state를 관리하고 업데이트합니다. React에서는 변경할 수 있는 state가 일반적으로 컴포넌트의 state 속성에 유지되며 setState()에 의해 업데이트됩니다.
...
폼을 렌더링하는 React 컴포넌트는 폼에 발생하는 사용자 입력값을 제어합니다. 이러한 방식으로 React에 의해 값이 제어되는 입력 폼 엘리먼트를 “제어 컴포넌트 (controlled component)“라고 합니다.
위는 공식 문서의 제어 컴포넌트의 설명이다이다.
https://ko.legacy.reactjs.org/docs/forms.html#controlled-components
간단히 말하자면, state가 렌더링을 제어하는 것을 제어 컴포넌트라고 하는데 onChange 방식이 제어 컴포넌트라고 할 수 있다.
const UseInput = () => {
const [input, setInput] = useState("");
const onChangeValue = (e) => {
setInput(e.target.value);
};
return (
<div>
<input onChange={onChangeValue} />
</div>
);
}
export default UseInput;
사용자가 입력한 값과 저장되는 값이 실시간으로 동기화 된다.
이러한 방식으로 데이터를 전부 받아올 수 있어 유효성 검사에 탁월한데
데이터를 하나하나 다 받아오므로 비효율적이거나 속도가 느릴 수 있는 단점이 있다.
대부분 경우에 폼을 구현하는데 제어 컴포넌트를 사용하는 것이 좋습니다. 제어 컴포넌트에서 폼 데이터는 React 컴포넌트에서 다루어집니다. 대안인 비제어 컴포넌트는 DOM 자체에서 폼 데이터가 다루어집니다.
모든 state 업데이트에 대한 이벤트 핸들러를 작성하는 대신 비제어 컴포넌트를 만들려면 ref를 사용하여 DOM에서 폼 값을 가져올 수 있습니다.
위는 공식 문서의 비제어 컴포넌트의 설명이다.
https://ko.legacy.reactjs.org/docs/uncontrolled-components.html
import React, { useRef } from 'react';
const UseRefInput = () => {
const inputRef = useRef(null);
const onSubmit = () => {
console.log(inputRef.current.value);
};
return (
<div>
<input ref={inputRef} />
<button type="submit" onClick={onSubmit}>
로그인
</button>
</div>
);
}
export default UseRefInput;
ref는 값을 업데이트 하여도 리랜더링 되지 않는 특성으로, 입력이 모두 되고난 후 ref를 통해 값을 한번에 가져와서 활용한다.
state로 값을 관리하지 않기 때문에 값이 바뀔 때마다 리랜더링을 하지 않고 값을 한번에 가져올 수 있는 성능상 이점이 있으나, 데이터를 완벽하게 가져올 수 없는 단점이 있다.
react hook form은 비제어 컴포넌트로 렌더링을 최적화할 수 있는 라이브러이다.
단순한 form을 처리하기 위해 state로 모든 값을 검사하여 리랜더링 하는 것보다 입력이 끝난 후 유효성 검사를 보여주어도 되고 더 빠른 검사를 할 수 있어 비제어 컴포넌트 방식인 react hook form을 많이 사용하는 것이라 생각한다.
1. 시작: npm, yarn 으로 설치하기
npm install react-hook-form
yarn add react-hook-form
2. useForm import하여 사용하기
import { useForm } from "react-hook-form";
const {
handleSubmit, // form onSubmit에 들어가는 함수
register, // onChange 등의 이벤트 객체 생성
watch, // register를 통해 받은 모든 값 확인
formState: { errors }, // errors: register의 에러 메세지 자동 출력
} = useForm();
3. 회원가입 유효성 검사
import * as S from "./style";
import BasicButton from "../../../components/Button/Button";
import { useForm } from "react-hook-form";
import { useRef } from "react";
const SignUpForm = () => {
const {
handleSubmit, // form onSubmit에 들어가는 함수
register, // onChange 등의 이벤트 객체 생성
watch, // register를 통해 받은 모든 값 확인
formState: { errors }, // errors: register의 에러 메세지 자동 출력
} = useForm();
const password = useRef(); // ref 생성
password.current = watch("password"); // watch를 이용하여 password 필드 값 가져오기, password.current에 값 넣어주기
const onChangeFormLib = (data) => {
console.log("회원가입 정보", data);
};
return (
<S.Form onSubmit={handleSubmit(onChangeFormLib)}>
<S.InputBox>
<label>이메일 </label>{" "}
<input
{...register("email", {
required: { value: true, message: "이메일을 입력해주세요" },
pattern: {
value: /^\S+@\S+$/i,
message: "이메일 형식이 올바르지 않습니다",
},
})}
/>
</S.InputBox>
{errors?.email && <S.ErrMsg>{errors?.email?.message}</S.ErrMsg>}
<S.InputBox>
<label>비밀번호 </label>{" "}
<input
name="password"
type="password"
{...register("password", {
required: { value: true, message: "비밀번호를 입력해주세요" },
minLength: {
value: 8,
message: "비밀번호 길이를 8자리 이상 입력해주세요",
},
})}
/>
</S.InputBox>
{errors.password && <S.ErrMsg>{errors?.password?.message}</S.ErrMsg>}
<S.InputBox>
<label>비밀번호 확인 </label>{" "}
<input
name="passwordConfirm"
type="password"
{...register("passwordConfirm", {
required: { value: true, message: "비밀번호 확인을 입력해주세요" },
validate: (value) => value === password.current, // password와 passwordConfirm이 같은지 체크하는 부분
})}
/>
</S.InputBox>
{errors?.passwordConfirm?.type === "required" && (
<S.ErrMsg>{errors?.passwordConfirm?.message}</S.ErrMsg>
)}
{errors?.passwordConfirm?.type === "validate" && (
<S.ErrMsg>비밀번호가 일치하지 않습니다.</S.ErrMsg>
)}
<BasicButton
variant={"primary"}
shape={"default"}
size={"full"}
>
회원가입
</BasicButton>
</S.Form>
);
};
export default SignUpForm;
입력 또는 선택 요소를 등록하고 React Hook Form에 유효성 검사 규칙을 적용할 수 있다.
예를 들어, 아래와 같이 ...register(검사할 속성 이름, 검사 패턴, 필수 속성 등) 를 작성하여 이름을 등록 후 두번째 인자로 받은 속성들로 유효성 검사를 할 수 있다.
<input
{...register("email", {
required: { value: true, message: "이메일을 입력해주세요" },
pattern: {
value: /^\S+@\S+$/i,
message: "이메일 형식이 올바르지 않습니다",
},
})}
/>
위 유효성 검사는 input은 email 유효성을 검사하는 것이고, 필수 속성이며 값을 입력하지 않으면 '이메일을 입력해주세요'라는 메세지가 나온다. 또 value의 pattern 에 맞는 형식이어야 하며 형식에 어긋나게 되면 '이메일 형식이 올바르지 않습니다' 라는 에러 메세지를 뱉어준다.
formState: { errors } 속성을 통해 위에서 검사한 값이 어긋나면 에러 메세지를 아래처럼 사용할 수 있다.
{errors?.email && <S.ErrMsg>{errors?.email?.message}</S.ErrMsg>}
이 외에도 다양한 속성을 적용하여 더 깊은 유효성 검사를 할 수 있다.
다음 게시물에서 yup 라이브러리를 함께 사용하는 법에 대해 알아볼 것이다.
감사합니다!! 도움이 많이 됐어요 ㅎㅎ