이전 프로젝트에서는 react-hook-form만 사용했는데, 이번에는 yup까지 같이 사용하게 됐다.
이전 프로젝트를 진행할때 현업에 종사하시는 멘토님께서 실무를 할때 react-hook-form과 yup을 같이 사용한다고 했기에 좋은 경험이 될거라 생각했다.
react-hook-form을 사용하는 이유
이전까지 모든 state를 직접 만들고, onchange함수도 일일히 만들어 바인딩해주는 등 노가다성 코딩을 했다.
이부분을 폼 라이브러리를 사용하면 더이상 노가다성 코딩을 하지 않아도 되며 굉장히 간편하다.
이전에 사용하던 onchange를 만들어 setState를 해주고 바인딩 하는 방법은 state가 변화할때마다 렌더링이 되기때문에 불필요한 렌더링이 지속적으로 일어나 굉장히 비효율적이었다.
또한 변화한 state를 받아서 다시 넣어주고 렌더링하기 때문에 굉장히 느리다.
하지만 react-hook-form은 imput의 값을 실시간으로 state에 반영하는것이 아닌 등록함수가 실행 될 때 한번에 처리하기 때문에 불필요한 렌더링이 제거되고 한번에 바꿔 렌더링하기 때문에 빠르고 효율적이다.
이렇게 처리하는 방식을 비제어 컴포넌트라고 하는데, 리액트 훅 폼은 비제어 컴포넌트다.
비제어 컴포넌트
: 바닐라 자바스크립트 처럼 sumit함수를 실행할 때 ref로 input값을 한번에 변경한다.
제어 컴포넌트
: 사용자의 입력을 기반으로 state를 실시간으로 관리(setState 사용). 쉽게 말해 입력이 될 때마다 state값이 실시간으로 변경된다.
한치의 오차도 용납할 수 없는 중요한 데이터를 저장하고 있다면 제어 컴포넌트를 이용하는게 좋다. 하지만 그런게 아니라면 비제어 컴포넌트를 이용해서 성능을 높여주는게 더 좋다.
검증 라이브러리 yup
가령 숫자인지, 문자인지, 최소 8자리인지, 특수문자가 들어가는지 등의 단계들이 있다.
yup은 이렇게 까다로운 검증과정을 대신해주는 라이브러리다.
yup과 같은 검증 라이브러리는 보통 form과 함께 사용한다.
따라서 우리는 리액트 훅 폼과 함께 사용할 것 이며, 함께 사용하실땐 리액트 훅 폼의 ‘Schema Validation’을 잘 보고 함께 사용하면 된다.
적용 코드
import { useMutation } from "@apollo/client"
import { useState } from "react"
import { CREATE_USER, LOGIN_USER } from "./Signup.queries"
import type {
IMutation,
IMutationCreateUserArgs,
IMutationLoginUserArgs,
} from "../../../commons/types/generated/types"
import { useRouter } from "next/router"
import { useRecoilState } from "recoil"
import { accessTokenState } from "../../../commons/stores"
import { useForm } from "react-hook-form"
import * as S from "./Signup.styles"
import * as yup from "yup"
import { yupResolver } from "@hookform/resolvers/yup"
const schema = yup.object({
email: yup
.string()
.email("이메일 형식이 적합하지 않습니다")
.required("이메일은 필수 입력입니다"),
password: yup
.string()
.min(4, "비밀번호는 최소 4자입니다")
.max(15, "비밀번호는 최대 15자입니다")
.required("비밀번호는 필수 입력입니다"),
})
export default function Signup(props) {
const router = useRouter()
const [, setAccessToken] = useRecoilState(accessTokenState)
const [email, setEmail] = useState("")
const [password, setPassword] = useState("")
const [name, setName] = useState("")
const [isActive, setIsActive] = useState(false)
const [createUser] = useMutation<
Pick<IMutation, "createUser">,
IMutationCreateUserArgs
>(CREATE_USER)
const [loginUser] = useMutation<
Pick<IMutation, "loginUser">,
IMutationLoginUserArgs
>(LOGIN_USER)
const onClickCreateUser = async (data) => {
....
}
const onClickLoginUser = async (data) => {
....
}
const { register, handleSubmit, formState } = useForm({
resolver: yupResolver(schema),
mode: "onChange",
})
return (
<>
<S.Container>
<S.Wrapper>
<h1>{props.signin ? "로그인" : "회원가입"}</h1>
<form
onSubmit={handleSubmit(
props.signin ? onClickLoginUser : onClickCreateUser
)}
style={{ width: "100%" }}
>
<S.Input type="text" placeholder="이메일" {...register("email")} />
<S.ErrorMessage>{formState.errors.email?.message}</S.ErrorMessage>
<S.Input
type="password"
placeholder="비밀번호"
{...register("password")}
/>
<S.ErrorMessage>
{formState.errors.password?.message}
</S.ErrorMessage>
{/* {props.signin ? "" : <Input {...register(name)} />} */}
<S.SubmitButton
style={{ backgroundColor: formState.isValid ? "#ffc700" : "" }}
// isActive={props.isActive}
onClick={
props.signin ? props.onClickLoginUser : props.onClickCreateUser
}
>
{props.signin ? "로그인" : "회원가입"}
</S.SubmitButton>
</form>
</S.Wrapper>
</S.Container>
</>
)
}
'project' 카테고리의 다른 글
왜 next.js인가? (1) | 2023.11.19 |
---|---|
S3, CloudFront, Route53을 이용해서 정적 웹 호스팅하기 (1) | 2023.11.12 |
docker (0) | 2023.09.19 |
협업때 자주 쓰이는 git 명령어 정리 (0) | 2023.09.07 |
초기 세팅 (0) | 2023.09.01 |