Next
[React] React-Hook-Form
React Hook Form이란?
사용하기 쉬운 유효성 검사와 함께, 성능이 좋고 유연하며 확장 가능한 폼 라이브러리입니다.
폼 라이브러리 종류
- React Form : 순수 React로 작성한 폼
- Redux Form : Redux 환경에서만 사용할 수 있다는 단점이 있음
- Formik : 한때 많이 쓰였지만, 클래스형에서 함수형으로 넘어오면서 사용이 줄어듦 (러닝 커브가 큼)
- React Hook Form : 함수형 컴포넌트용 Hook 기반 폼 (간단함, 당시 실무에서 가장 많이 사용)
React Hook Form을 쓰는 이유
Less code. More performant
React Hook Form은 불필요한 리렌더링을 없애면서 작성해야 하는 코드의 양도 줄여 줍니다.
React Hook Form은 입력할 때마다 리렌더링되지 않습니다.
state가 바뀌면 리렌더링되는 것 아닌가요? 비제어 컴포넌트 방식으로 만들어져 있어서 입력할 때마다 리렌더링되지 않습니다.
useRef는 내용이 바뀌어도 알려 주지 않습니다.
.current속성을 바꿔도 리렌더링되지 않습니다. React가 ref를 DOM 노드에 연결하거나 분리할 때 코드를 실행하고 싶다면 콜백 ref를 사용할 수 있습니다. React 공식 문서 - useRef
제어 컴포넌트와 비제어 컴포넌트 제어 컴포넌트는 입력할 때마다 setState가 실행되어 리렌더링이 일어납니다. 1,500자 분량의 이력서를 작성하면 버벅이는 것이 사용자 눈에 보일 수 있습니다. (성능 저하)
제어 컴포넌트가 필요한 경우
신용카드 번호를 입력할 때
처음과 마지막 두 글자를 제외한 나머지를 *로 보여 줘야 하는 경우
진짜값: 1234-1234-1234-1234
보여주는값: 12**-****-****-**34
<input type="text" value={보여주는값}/>
비제어 컴포넌트는 리렌더링이 발생하지 않습니다. (ref) document.getElementById()처럼 useRef로 DOM을 직접 참조해 비제어 컴포넌트를 만들 수 있습니다. 1,500자 분량의 이력서를 작성해도 버벅이지 않습니다. (성능 좋음)
사용법
signup.container.tsx
export default function Singup() {
const router = useRouter();
const { register, handleSubmit, formState } = useForm<IFormData>({
resolver: yupResolver(schema),
});
const [createUser] = useMutation(CREATE_USER);
const onClickSubmit = async (data: IFormData) => {
try {
const result = await createUser({
variables: {
createUserInput: {
...data,
},
},
});
console.log(result);
alert("회원가입을 해주셔서 감사합니다.");
router.push("/");
} catch (error) {
ErrorModal("회원가입", error.message);
}
};
return (
<SingupUI
register={register}
handleSubmit={handleSubmit}
formState={formState}
onClickSubmit={onClickSubmit}
/>
);
}
Container에서 useForm을 선언하고, Presenter에 register, handleSubmit, formState를 내려 보냅니다. register(onChange), handleSubmit(onClick), formState(state)
signup.parsenter.tsx
export default function SingupUI(props) {
return (
<>
<S.Wrapper>
<S.FormWrap onSubmit={props.handleSubmit(props.onClickSubmit)}>
<S.Title>AniMap 회원가입</S.Title>
<input type="text" {...register("email")} />
<div>{formState.errors.email?.message}</div>
<input type="password" {...register("password")} />
<div>{formState.errors.password?.message}</div>
<input type="text" {...register("name")} />
<div>{formState.errors.name?.message}</div>
<S.ButtonWrap>
<Button01 text="가입하기" />
</S.ButtonWrap>
</S.FormWrap>
</S.Wrapper>
</>
);
}
form 안의 button은 type을 지정하지 않으면 기본으로 submit이 되고, 클릭하면 form의 onSubmit이 호출됩니다. handleSubmit으로 onClickSubmit을 감싸면 입력값을 전달받을 수 있습니다.
props.formState.errors.필드명.message는 Yup 유효성 검사에서 에러가 났을 때의 메시지입니다.
유효성 검사 라이브러리 Yup
Yup이란? Yup은 런타임 값 파싱과 유효성 검사를 위한 스키마 빌더입니다. 스키마를 정의하고 값을 변환하거나 검증할 수 있으며, 복잡하고 서로 의존하는 유효성 검사도 표현할 수 있습니다.
signup.validation.ts
import * as yup from "yup";
export const schema = yup.object({
email: yup
.string()
.required("이메일을 입력해주세요.")
.email("이메일 형식에 맞춰주세요"),
password: yup
.string()
.required("패스워드를 입력해주세요.")
.matches(
/^(?=.*?[a-zA-Z])(?=.*?[0-9])(?=.*?[#?!@$%^&*-]).{8,16}$/,
"8자~16자, 숫자/영어대소문자/특수문자를 모두 포함해주세요"
),
name: yup
.string()
.required("이름을 입력해주세요.")
.max(8, "8글자 이하로 작성해주세요"),
});
Yup을 사용하면 유효성 검사 코드를 더 간단하고 명확하게 작성할 수 있습니다.
댓글 0