form 관련 훅으로, 비제어 컴포넌트 방식으로 구현되어 있어 렌더링 이슈를 해결가능하다. 난 회원가입에서의 유저 정보들을 yup을 활용하여 구현한 유효성검사와 함께 react-hook-form을 적용해보았다.
아래 글에 왜 react-hook-form을 쓰면 좋은지 적용 과정과 함께 아주 잘 정리해놓으셨다! 🙌
🔗 [tech.inflab.com] react-hook-form을 선택한 이유와 적용 과정
일단 아래 명령어를 통해 react-hook-form
과 yup
을 설치해준다.
npm install react-hook-form yup @hookform/resolvers
import할 것도 챡챡 해주기!
// import해줄것!
import { useForm, SubmitHandler } from "react-hook-form";
import { yupResolver } from "@hookform/resolvers/yup";
import * as yup from "yup";
글구 form 유효성 검사를 해주는 yup을 활용하여 schema를 설정해준다. 나는 validation을 따로 hooks 폴더에 분리해주었다.
// validationYup.tsx
// yup schema 설정
const schema = yup.object().shape({
name: yup
.string()
.min(3, "닉네임을 3글자 이상으로 입력해주세요.")
.required("닉네임을 필수로 입력해주세요."),
email: yup
.string()
.email("이메일 형식을 맞춰서 입력해주세요.")
.required("이메일을 필수로 입력해주세요."),
password: yup
.string()
.min(3, "비밀번호를 3~16글자로 입력해주세요.")
.max(16, "비밀번호를 3~16글자로 입력해주세요.")
.matches(
/^(?=.*[a-zA-Z])((?=.*\d)(?=.*\W))/,
"비밀번호에 영문, 숫자, 특수문자를 포함해주세요."
)
.required("비밀번호를 필수로 입력해주세요."),
confirmPassword: yup
.string()
.oneOf([yup.ref("password"), null], "비밀번호가 일치하지 않습니다."),
});
react-hook-form 적용은 공식문서에 TS로 적용하는 방법도 잘 나와있기 때문에 그거 고대로 따라하면 된다~!
// 타입 지정
type Inputs = {
name: string;
email: string;
password: string;
confirmPassword: string;
};
// react-hook-form 적용하여 회원가입폼 구현하기
const JoinForm = () => {
const {
register,
handleSubmit,
reset, // 필드값 초기화
formState: { isSubmitting, errors },
} = useForm<Inputs>({ resolver: yupResolver(schema), mode: "onChange"});
// 여기서 mode: "onChange"를 써줘야 값이 바뀔 때마다 유효성 검사를 해준다!
const onSubmit: SubmitHandler<Inputs> = async (data) => {
console.log(data);
};
return (
<Container>
{/* handleSubmit() 이용시 새로고침 현상 X => e.preventDefualt() 설정 필요없다! */}
<Form id="join" onSubmit={handleSubmit(onSubmit)}>
<LoginInput id="name" type="text" register={register("name")}>
NickName
</LoginInput>
{errors.name && <Message>{errors.name.message}</Message>}
...
{/* disabled 속성으로 isSubmitting 값을 주면 폼 제출이 완료 되기 전에는 버튼 비활성화해줌! */}
<BasicBtn disabled={isSubmitting} type="submit">
Sign up
</BasicBtn>
</Form>
</Container>
);
};
구현하는 과정에서 좀 애먹었던 내용쓰,, 그냥 input 태그에 적용하면 잘 되는데 재사용을 위해 따로 분리해두었던 Input 컴포넌트를 사용시 값이 잘 안 넘어가서 data 값이 undefined
가 뜨는 바람에 에러 메세지 또한 출력이 되지 않았다,,🥲
폭풍구글링을 통해 아래 블로그 글을 참고했더니 드뎌 잘 작동됨~! 🥳
🔗 [에러 해결 참고자료] react-hook-form과 React.forwardRef() 에러
분리한 Input 컴포넌트에서
forwardRef
를 따로 적용한 후에 hook-form을 적용하는 부분인{…register(’name’)}
이 값을 Input 컴포넌트로 넘겨줘야 하는데 이에 대한 타입을UseFormRegisterReturn
으로 따로 지정해준다.
이후 여기서 input 속성으로 props.register를 불러오면 끄읏-
// LoginInput.tsx
import { UseFormRegisterReturn } from "react-hook-form";
interface InputType {
children: React.ReactNode;
id: string;
type?: string;
}
interface Props extends InputType {
register?: UseFormRegisterReturn;
}
const LoginInput = React.forwardRef((props: Props, ref) => {
return (
<input
id={props.id}
type={props.type}
autoComplete="off"
ref={ref}
{...props.register}
/>
);
});
💫 위의 과정을 통해 구현해본 간단 회원가입폼 컴포넌트!
🔗 react-hook-form & yup으로 구현한 회원가입폼 배포 링크
react-hook-form를 한번 적용해보는 과정이 수월하진 않았지만 한번 사용해봤으니까 다른 플젝에다가 가져다가 쓰면 무척이나 편리할 것 같은 느낌!
특히, 회원가입, 로그인 부분에서 value, onChange로 값 관리를 하지 않아도 된다는 점이 맘에 듬! 👏👏👏