"use client";
import { useState } from "react";
const SignInForm = () => {
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
return (
<form
onSubmit={(e) => {
e.preventDefault();
}}
className="flex flex-col gap-4 p-5 items-center w-full m-auto"
>
<div className="flex flex-col gap-2">
<label htmlFor="email">Email</label>
<input
id="email"
type="email"
value={email}
onChange={(e) => setEmail(e.target.value)}
placeholder="Email"
className="text-black"
/>
</div>
<div className="flex flex-col gap-2">
<label htmlFor="password">Password</label>
<input
type="password"
value={password}
onChange={(e) => setPassword(e.target.value)}
placeholder="Password"
className="text-black"
/>
</div>
<button
className="bg-gray-800 text-white px-4 py-2 rounded-md"
type="submit"
>
Sign In
</button>
</form>
);
};
export default SignInForm;
전형적인 리액트의 로그인 컴포넌트이다.
useState로 아이디 비밀번호 state를 만들어주고, 제어 컴포넌트로 값의 변화마다 리렌더링 시켜준다.
단순 로그인 페이지면 어느정도 볼만하겠지만, 회원가입이나 혹은 input이 굉장히 많은 페이지에선 절대적인 코드의 양이 어마무시하게 많아진다.
state생성, state핸들링, submit함수, submit전 데이터 전처리, 각 state에 대한 유효성 검사 등...
무엇보다도 한 state가 변화할때마다 해당 state와 연관된 모든 컴포넌트, 그 자식 컴포넌트가 모두 리렌더링 되는 것이다.
그리하여 그러한 코드의 양을 줄일 수 있고, 리렌더링관리를 쉽게 할 수 있는 react-hook-form을 사용해보고자 한다.
npm i react-hook-form
yarn/pnpm add react-hook-form
1. useForm, handleSubmit
"use client";
import { useForm } from "react-hook-form";
const SignInForm = () => {
const { register, handleSubmit, formState } = useForm();
const onSubmit = () => {};
return (
<form onSubmit={handleSubmit(onSubmit)} className="flex flex-col gap-4 p-5 items-center w-full m-auto">
라이브러리를 설치하고 useForm을 가져와서 그 안의 register, handleSubmit, formState를 가져와준다.
그리고 submit을 위한 onSubmit함수를 생성해주고, form태그의 onSubmit에 handleSubmit으로 감싸서 넣어준다.
import { FieldValues, useForm } from "react-hook-form"
const onSubmit = (value: FieldValues) => {
console.log(value)
};
onSubmit에서는 value를 인자로 받아주고 타입은 react-hook-form의 FieldValues를 지정해준다.
2. register
<input
id="email"
type="email"
value={email}
onChange={(e) => setEmail(e.target.value)}
placeholder="Email"
className="text-black"
/>
기존에 우리는 다양한 input에 value, onChange를 사용해 state를 관리해주었다.
이제는 useForm이 제공해주는 register을 사용하면 된다.
<input
{...register("email", {
required: true,
pattern: {
value: /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/,
message: "Invalid email address",
},
})}
id="email"
type="email"
placeholder="Email"
className="text-black"
/>
기존 value, onChange를 제거하고 register을 넣어준다. 그리고 첫 인자로는 해당 값의 id를 넣어준다 해당 필드는 이메일을 관리하는 필드이기때문에 email을 넣어주고, 두번쨰 인자로는 option을 객체 형식으로 지정하면 된다.
해당 option은 docs에서 참고하면 된다.
onSubmit의 인자로 받은 value가 저렇게 이쁜 모습으로 알아서 들어오는 것을 볼 수 있다.
3. formState
formState는 어떤 값을 가지고 있을지 콘솔을 찍어보자.
defaultValues, dirtyFields, errors,isValid
여기서 defaultValues가 undefined로 표시되고 있다. 우리가 useForm에서 설정해주지 않았기 때문이다.
const { register, handleSubmit, formState } = useForm({
defaultValues: {
email: "123",
},
});
이렇게 defaultValues를 지정해주면 렌더링시 해당 기본값이 필드에 들어가 있다.
formState는 에러도 보유하고 있다.
우리가 required로 설정한 값
이 특정 패턴을 지키지 않았거나, 데이터가 없을 때 미리 지정해둔 메시지를 보내주는 것이다.
<div className="flex flex-col gap-2">
<label htmlFor="email">Email</label>
<input
{...register("email", {
required: true,
pattern: {
value: /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/,
message: "Invalid email address",
},
})}
id="email"
type="email"
placeholder="Email"
className="text-black"
/>
{formState.errors?.email?.message}
</div>
따라서 우리가 이렇게 에러메시지를 넣어주면 화면에 출력된다.
또한 formState의 isValid를 사용하면 모든 formData값이 유효한지 검사해주어 bool값에따라 원하는 기능을 제어할 수 있다.
<button className="bg-gray-800 text-white px-4 py-2 rounded-md" type="submit" disabled={!formState.isValid}>
Sign In
</button>
예를 들어 이런 식으로 formState가 false일때는 버튼을 disabled시킬 수 있다.
"use client";
import { FieldValues, useForm } from "react-hook-form";
const LoginTest = () => {
const { register, handleSubmit, formState } = useForm({
mode: "onChange",
defaultValues: {
email: "test@test.com",
password: "",
},
});
const onSubmit = (value: FieldValues) => {};
return (
<form onSubmit={handleSubmit(onSubmit)}>
<div className="flex flex-col justify-center items-center">
<div className="border border-solid border-black">
<label htmlFor="email">이메일</label>
<input
id="email"
type="text"
{...register("email", {
required: true,
pattern: {
value: /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/,
message: "Invalid email address",
},
})}
/>
</div>
<div className="border border-solid border-black">
<label htmlFor="password">비밀번호</label>
<input
id="password"
type="password"
{...register("password", {
required: true,
})}
/>
</div>
<button type="submit" className="border border-solid border-black">
로그인
</button>
</div>
</form>
);
};
export default LoginTest;
'2차 공부 > TIL' 카테고리의 다른 글
말이안되는 요청코드 rpc로 쉽게? 해결하기 (3) | 2024.10.26 |
---|---|
24.10.20 NextJS react-hook-form Zod (0) | 2024.10.20 |
24.10.15 tailwind에서 제공하지 않는 style속성 사용하기 (0) | 2024.10.15 |
24.10.14 supabase.insert, promise.all과 transaction (1) | 2024.10.15 |
24.10.11 react에서 리스트 매핑중 key를 사용해야하는 이유 (0) | 2024.10.11 |