회원가입 기능을 구현하려고 했을 때 form 태그를 사용하면 필요한 데이터, 사용자가 입력한 데이터만 쏙쏙 빼서 데이터를 정제하고 서버로 전달할 수 있습니다. 매우 편리한 태그입니다. 이 태그를 react에 맞춰진 라이브러리를 찾아보다가 react-hook-form을 찾게 되었습니다.
React Hook Form이라고 해서 React에서 자체 지원해주는 hook인줄 알았는데 아니에요. react-hook-form이라는 라이브러리를 install 해서 사용하는 겁니다. React의 장점 중 하나는 라이브러리의 세계가 넓습니다.
https://react-hook-form.com/get-started
React Hook Form 라이브러리 설치
npm install react-hook-form
위와 같이 설치해줍니다.
React Hook Form 사용법 - 기본
doc에 있는 튜토리얼을 보고 따라서 작성했습니다.
doc에 영상도 함께 첨부되어 있어서 보기 편했습니다. 만약 자세하게 알아보고 사용해보고 싶으신 분들은 사이트 내용 확인해보시면 될 것 같습니다.
import { useForm, SubmitHandler } from "react-hook-form";
interface SignForm {
name: string;
email: string;
password: string;
}
function SignUp() {
// react-hook-form 사용 함수
// register : 등록
// handleSubmit : submit을 클릭하는 함수
// watch : 실시간 변화하는 값 확인 함수
// formState : form 내 데이터 값 상태 확인
const { register, handleSubmit, watch, formState: { errors } } = useForm<SignForm>();
// submit 클릭시 실행 함수 onSubmit
const onSubmit: SubmitHandler<SignForm> = (data) => console.log(data)
// 실시간 확인하는 함수 watch
const name = watch("name");
return (
<form onSubmit={handleSubmit(onSubmit)}>
<input id="name" placeholder="Name"
{...register("name", {
required: "This is required.",
minLength: { value: 2, message: "Min Length is 2" }
})}
/>
<p> {errors.name?.message}</p>
<p> {name}</p>
</form>
);
}
export default SignUp;
이렇게 작성하는 코드가 기본적으로 사용하는 react-hook-form입니다.
여기에서 UI를 더 예쁘게 사용하려면 라이브러리를 사용하면 됩니다. react-hook-form은 외부 UI 구성 요소 라이브러리와 쉽게 통합할 수 있습니다. 구성요소가 입력 참조를 노출하지 않는 경우에는 등록 프로세스를 처리하는 Controller 구성 요소를 사용해야 합니다.
React Hook Form 사용법 - UI 라이브러리와 통합(Controller)
https://react-hook-form.com/docs/usecontroller/controller
MUI와 통합
https://codesandbox.io/p/sandbox/react-hook-form-v7-controller-5h1q5?file=%2Fsrc%2FMui.js%3A89%2C14
아래 코드는 하단의 참고 블로그의 코드입니다. + 일부 수정
import { TextField } from "@mui/material"
import { useForm, Controller } from "react-hook-form"
type FormValues = {
ReactDatepicker: string
}
function App() {
// useForm 데이터 관리
const { control, handleSubmit } = useForm();
const handle = (data:any) =>{
console.log(data)
}
return (
<form onSubmit={handleSubmit(handle)}>
<Controller
control={control}
name="email"
defaultValue={''}
rules={{
required: 'Email ID is required',
pattern: {
value: /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i,
message: 'Invalid email address',
},
minLength: {
value: 6,
message: 'Email must be at least 6 characters',
},
}}
render={({ field: { onChange, onBlur, value, ref }, fieldState:{error} }) => (
<TextField
label="name2"
onChange={onChange} // send value to hook form
value={value}
error={error !== undefined}
helperText={error && error.message}
/>
)}
/>
</form>
)
}
control : useForm, React Hook Form에 넣는 값
name : 역할
pattern : 유효성 검사
minLength, maxLength : 최소, 최대 길이
render : 컴포넌트
최종 코드
import { useState } from "react";
// react-router-dom components
import { Link } from "react-router-dom";
import { useForm, SubmitHandler, Controller } from "react-hook-form";
import { TextField } from "@mui/material";
// @mui material components
import Card from "@mui/material/Card";
import Checkbox from "@mui/material/Checkbox";
// Soft UI React components
import SoftBox from "components/SoftBox";
import SoftTypography from "components/SoftTypography";
import SoftInput from "components/SoftInput";
import SoftButton from "components/SoftButton";
import BaseLayout from "pages/LayoutContainers/Base";
import Socials from "components/Socials";
import Separator from "components/Separator";
// Images
import curved6 from "assets/images/curved14.jpg";
type FormValues = {
name: string
email: string
password: string
checkpassword: string
}
function SignUp() {
const [agreement, setAgremment] = useState(true);
//react-hook-form
const { handleSubmit, control } = useForm<FormValues>();
// 제출 시 실행할 함수
const onSubmit: SubmitHandler<FormValues> = (data) => {
if (data.password == data.checkpassword){
console.log("node api 전송")
}
};
return (
<BaseLayout
title="Welcome!"
description="Use these awesome forms to login or create new account in your project for free."
image={curved6}
>
<Card>
<SoftBox pt={2} pb={3} px={3}>
<form onSubmit={handleSubmit(onSubmit)}>
<SoftBox mb={2}>
<SoftTypography variant="button" color="text" fontWeight="regular">
Name
</SoftTypography>
<Controller
control={control}
name="name"
rules={{
required: 'Name is required',
pattern: {
value: /^[가-힣a-zA-Z]/,
message: ""
},
minLength: {
value: 1,
message: 'Name must be at least 1 characters',
},
}}
render={({ field: { onChange, value, ref }, fieldState: {error} }) => {
// console.log("name error : ", error)
return (
<>
<SoftInput
id="name"
type="text"
onChange={onChange} // send value to hook form
placeholder="Name"
value={value || ""}
ref={ref} // ref 전달
/>
<SoftTypography variant="button" color="red" fontWeight="light">
{error?.message}
</SoftTypography>
</>
)}
}
/>
</SoftBox>
<SoftBox mb={2}>
<SoftTypography variant="button" color="text" fontWeight="regular">
Email
</SoftTypography>
<Controller
control={control}
name="email"
rules={{
required: 'Email is required',
pattern: {
value: /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i,
message: ""
},
minLength: {
value: 3,
message: 'Email must be at least 3 characters',
},
}}
render={({ field: { onChange, value, ref }, fieldState: {error} }) => {
// console.log("email error : ", error)
return(
<>
<SoftInput
id="email"
type="email"
onChange={onChange} // send value to hook form
placeholder="Email"
value={value || ""}
ref={ref} // ref 전달
/>
<SoftTypography variant="button" color="red" fontWeight="light">
{error?.message}
</SoftTypography>
</>
)}}
/>
</SoftBox>
<SoftBox mb={2}>
<SoftTypography variant="button" color="text" fontWeight="regular">
Password
</SoftTypography>
<Controller
control={control}
name="password"
rules={{
required: 'Password is required',
pattern: {
value: /^[가-힣a-zA-Z]/,
message: ""
},
minLength: {
value: 1,
message: 'Password must be at least 1 characters',
},
}}
render={({ field: { onChange, value, ref }, fieldState: {error} }) => {
console.log("password error : ", error)
return(
<>
<SoftInput
id="password"
type="password"
onChange={onChange} // send value to hook form
placeholder="Password"
value={value || ""}
ref={ref} // ref 전달
/>
<SoftTypography variant="button" color="red" fontWeight="light">
{error?.message}
</SoftTypography>
</>
)}}
/>
</SoftBox>
<SoftBox mb={2}>
<SoftTypography variant="button" color="text" fontWeight="regular">
Password Check
</SoftTypography>
<Controller
control={control}
name="checkpassword"
rules={{
required: 'Check password is required',
pattern: {
value: /^[가-힣a-zA-Z]/,
message: ""
},
minLength: {
value: 1,
message: 'password must be at least 1 characters',
},
validate: (value) => (value == control._formValues.password) || "Passwords do not match"
}}
render={({ field: { onChange, value, ref }, fieldState: {error} }) => {
console.log("check password error : ", error, control)
return(
<>
<SoftInput
id="checkpassword"
type="password"
onChange={onChange} // send value to hook form
placeholder="Check-password"
value={value || ""}
ref={ref} // ref 전달
/>
<SoftTypography variant="button" color="red" fontWeight="light">
{error?.message}
</SoftTypography>
</>
)}}
/>
</SoftBox>
<SoftBox mt={4} mb={1}>
<SoftButton type="submit" variant="gradient" color="dark" fullWidth >
sign up
</SoftButton>
</SoftBox>
</form>
<SoftBox mt={3} textAlign="center">
<SoftTypography variant="button" color="text" fontWeight="regular">
Already have an account?
<SoftTypography
component={Link}
to="/authentication/sign-in"
variant="button"
color="black"
fontWeight="bold"
textGradient
>
Sign in
</SoftTypography>
</SoftTypography>
</SoftBox>
</SoftBox>
</Card>
</BaseLayout>
);
}
export default SignUp;
이름, 이메일, 비밀번호, 비밀번호확인 4가지로 Controller를 생성하여 정규 표현식을 확인하고 함수에서 로그를 찍을 수 있도록 코드를 작성했습니다.
- 이름, 이메일, 비밀번호, 비밀번호확인 Controller 생성
- 정규표현식
- validate로 값 확인하는 함수 (비밀번호와 비밀번호 확인 인풋값 비교)
render부분에서 태그를 넣는 부분과 error 메세지를 넣어줬고 rules의 pattern에 정규표현식을 잘못 적어서 애를 먹었네요.. 꼭 정규표현식 제대로 작동 되는지 디버깅해보세요!
여기서 사용되는 SoftButton, SoftInput, SoftTypography 등은 프로토타입으로 button, input, p 태그를 커스텀하는 mui를 사용했습니다. 모두 일반 태그로 변경하시고 type과 name 지정을 잘 해주면 될 것입니다!
참고
https://react-hook-form.com/docs/usecontroller/controller
https://velog.io/@boyeon_jeong/React-Hook-Form
'프론트 > React Native, React' 카테고리의 다른 글
[오픈소스] React 프로젝트에서 사용할 만한 오픈소스와 라이브러리 10가지 (18) | 2024.11.13 |
---|---|
[React] React Hook useReducer 파헤치기, useReducer란?(Typscript) (4) | 2024.11.07 |
[리액트] 리액트(React)의 사용 이유와 장단점 (2) | 2023.10.10 |
[리액트 네이티브] non-std C++ exception error 해결하는 방법 (0) | 2023.08.09 |
[리액트네이티브] react-native 체크 박스 만들기 (Expo) (0) | 2023.07.09 |