회원가입기능을 구현할때 react-hook-form를 요긴하게 쓸 수 있다.
더 간결하고 직관적으로 코드를 작성할 수 있다.
그 이유는 회원가입을 구현할때 여러 입력값에 대한 상태관리를 해줘야하는데 이 경우 복잡해지기 쉽상이고 상태관리에 대한 번거러움이 있기 때문이다.
입력값의 변화에 따라 전체 폼을 다시 렌더링하는 것이 아니라 필요한 입력 요소만 렌더링한다는 큰 이점이 있다.
폼 유효성 검사가 내장되어 있어서 사용자의 입력값을 쉽게 유효성을 검증하고 에러를 처리할 수 있다.
즉, react-hook-form은 복잡한 폼 상태를 관리하고 폼을 구현할 때 개발자에게 많은 편의성을 제공하는 데 유용한 도움을 주는 라이브러리다.
npm install react-hook-form
( TS를 지원한다! )
공식 홈페이지에서 사용예에 대한 코드다.
import { useForm, SubmitHandler } from "react-hook-form"
type Inputs = {
example: string
exampleRequired: string
}
export default function App() {
const {
register,
handleSubmit,
watch,
formState: { errors },
} = useForm<Inputs>()
const onSubmit: SubmitHandler<Inputs> = (data) => console.log(data)
console.log(watch("example")) // watch input value by passing the name of it
return (
/* "handleSubmit" will validate your inputs before invoking "onSubmit" */
<form onSubmit={handleSubmit(onSubmit)}>
{/* register your input into the hook by invoking the "register" function */}
<input defaultValue="test" {...register("example")} />
{/* include validation with required or other standard HTML validation rules */}
<input {...register("exampleRequired", { required: true })} />
{/* errors will return when field validation fails */}
{errors.exampleRequired && <span>This field is required</span>}
<input type="submit" />
</form>
)
}
컴포넌트를 훅에 등록(register)한다.
그 결과 해당 컴포넌트의 값이 폼 유효성 검사와 제출 모두에서 사용할 수 있다.
{...register(fields)}
위의 코드에서 찾아보자면 아래와 같다.
<form onSubmit={handleSubmit(onSubmit)}>
{/* register your input into the hook
by invoking the "register" function */}
<input defaultValue="test" {...register("example")} />
</form>
기존 HTML 표준과 일치하여 폼 유효성 검사를 간편하게 처리한다.
import { useForm, SubmitHandler } from "react-hook-form"
interface IFormInput {
firstName: string
lastName: string
age: number
}
export default function App() {
const { register, handleSubmit } = useForm<IFormInput>()
const onSubmit: SubmitHandler<IFormInput> = (data) => console.log(data)
return (
<form onSubmit={handleSubmit(onSubmit)}>
<input {...register("firstName", { required: true, maxLength: 20 })} />
<input {...register("lastName", { pattern: /^[A-Za-z]+$/i })} />
<input type="number" {...register("age", { min: 18, max: 99 })} />
<input type="submit" />
</form>
)
}
이렇게 {}안에 필요한 옵션들을 추가해주면 된다.
더 많은 옵션들과 사용예는 아래 링크에서 자세히 볼 수 있다.
https://react-hook-form.com/docs/useform/register
폼 유효성 react-hook
const { register, handleSubmit } = useForm<IFormInput>()
useForm은 폼을 쉽게 관리하기 위한 커스텀 훅이다. 선택적으로 하나의 객체를 인수로 받는다
useForm: UseFormProps
mode: onChange | onBlur | onSubmit | onTouched | all = 'onSubmit'
유효성 검사는 handleSubmit 함수를 호출하여 발생하는 onSubmit 이벤트 중에 발생한다.
uncontrolled/controlled inputs을 등록한다
register: (name: string, RegisterOptions?) => ({ onChange, onBlur, name, ref })
const { onChange, onBlur, name, ref } = register('firstName');
// include type check against field path with the name you have supplied.
<input
onChange={onChange} // assign onChange event
onBlur={onBlur} // assign onBlur event
name={name} // assign name prop
ref={ref} // assign ref prop
/>
// same as above
<input {...register('firstName')} />
전체 form State에 대한 정보가 포함되어 있다. 사용자의 상호 작용을 추적하는 데 도움이 된다.
import React from "react";
import { useForm } from "react-hook-form";
export default function App() {
const {
register,
handleSubmit,
// Read the formState before render to subscribe the form state through the Proxy
formState: { errors, isDirty, isSubmitting, touchedFields, submitCount },
} = useForm();
const onSubmit = (data) => console.log(data);
return (
<form onSubmit={handleSubmit(onSubmit)}>
<input {...register("test")} />
<input type="submit" />
</form>
);
}
import ReactDatePicker from "react-datepicker"
import { TextField } from "@material-ui/core"
import { useForm, Controller } from "react-hook-form"
type FormValues = {
ReactDatepicker: string
}
function App() {
const { handleSubmit, control } = useForm<FormValues>()
return (
<form onSubmit={handleSubmit((data) => console.log(data))}>
<Controller
control={control}
name="ReactDatepicker"
render={({ field: { onChange, onBlur, value, ref } }) => (
<ReactDatePicker
onChange={onChange} // send value to hook form
onBlur={onBlur} // notify when input is touched/blur
selected={value}
/>
)}
/>
<input type="submit" />
</form>
)
}
useWatch 함수는 리렌더링이 관련 커스텀 훅 내에서만 일어나도록 제어함으로써 성능 향상을 도모할 수 있다.
import React from "react";
import { useForm, useWatch, Control } from "react-hook-form";
interface FormInputs {
firstName: string;
lastName: string;
}
function FirstNameWatched({ control }: { control: Control<FormInputs> }) {
const firstName = useWatch({
control,
name: "firstName", // name을 제공하지 않으면 전체 폼을 감시한다. 또는 ['firstName', 'lastName']와 같이 여러 값 감시 가능
defaultValue: "default", // 렌더링 전의 기본 값
});
return <p>Watch: {firstName}</p>; // firstName이 변경될 때 커스텀 훅 수준에서만 리렌더링된다.
}
function App() {
const { register, control, handleSubmit } = useForm<FormInputs>();
const onSubmit = (data: FormInputs) => {
console.log(data);
};
return (
<form onSubmit={handleSubmit(onSubmit)}>
<label>First Name:</label>
<input {...register("firstName")} />
<input {...register("lastName")} />
<input type="submit" />
<FirstNameWatched control={control} />
</form>
);
}
useWatch를 사용하여 FirstNameWatched 컴포넌트를 통해 firstName의 변화를 감시하고, 해당 값이 변경될 때 커스텀 훅 수준에서만 리렌더링되도록 한다.
watch 메서드는 지정된 입력값들을 감시하고 해당 값들을 반환한다. 입력값의 값을 렌더링하거나 조건에 따라 어떤 것을 렌더링할지 결정하는 데 유용하다.
특정한 입력값들을 감시하여 그 값들을 받아올 수 있어서, 해당 값에 따라 조건부로 화면을 렌더링하는 데 활용된다.
import React from "react"
import { useForm } from "react-hook-form"
interface IFormInputs {
name: string
showAge: boolean
age: number
}
function App() {
const {
register,
watch,
formState: { errors },
handleSubmit,
} = useForm<IFormInputs>()
const watchShowAge = watch("showAge", false) // you can supply default value as second argument
const watchAllFields = watch() // when pass nothing as argument, you are watching everything
const watchFields = watch(["showAge", "age"]) // you can also target specific fields by their names
// Callback version of watch. It's your responsibility to unsubscribe when done.
React.useEffect(() => {
const subscription = watch((value, { name, type }) =>
console.log(value, name, type)
)
return () => subscription.unsubscribe()
}, [watch])
const onSubmit = (data: IFormInputs) => console.log(data)
return (
<>
<form onSubmit={handleSubmit(onSubmit)}>
<input {...register("name", { required: true, maxLength: 50 })} />
<input type="checkbox" {...register("showAge")} />
{/* based on yes selection to display Age Input*/}
{watchShowAge && (
<input type="number" {...register("age", { min: 50 })} />
)}
<input type="submit" />
</form>
</>
)
}
<Form />
컴포넌트를 사용하여 라이브러리의 내장 제출 처리 기능을 사용할 수 있다.
import { Form } from "react-hook-form"
function App() {
const { register, control } = useForm()
return (
<Form
action="/api/save" // Send post request with the FormData
// encType={'application/json'} you can also switch to json object
onSuccess={() => {
alert("Your application is updated.")
}}
onError={() => {
alert("Submission has failed.")
}}
control={control}
>
<input {...register("firstName", { required: true })} />
<input {...register("lastName", { required: true })} />
<button>Submit</button>
</Form>
)
}
watch 메서드를 사용하여 showAge에 따라 나이 입력란을 표시하거나 숨기는 예시를 보여준다다.
스키마 기반의 폼 유효성 검사를 Yup, Zod, Superstruct 및 Joi와 함께 지원한다. useForm에 스키마를 선택적 구성으로 전달하여 스키마에 따라 입력 데이터를 유효성 검사하고 오류 또는 유효한 결과를 반환합니다.
1단계 : yup설치
npm install @hookform/resolvers yup
2단계 : 유효성 검사를 위해 스키마를 준비하고 React Hook Form으로 입력 요소를 등록한다.
import { useForm } from "react-hook-form"
import { yupResolver } from "@hookform/resolvers/yup"
import * as yup from "yup"
const schema = yup
.object({
firstName: yup.string().required(),
age: yup.number().positive().integer().required(),
})
.required()
export default function App() {
const {
register,
handleSubmit,
formState: { errors },
} = useForm({
resolver: yupResolver(schema),
})
const onSubmit = (data) => console.log(data)
return (
<form onSubmit={handleSubmit(onSubmit)}>
<input {...register("firstName")} />
<p>{errors.firstName?.message}</p>
<input {...register("age")} />
<p>{errors.age?.message}</p>
<input type="submit" />
</form>
)
}