[React] React Hook Form의 useForm 사용기
React hook form은 리액트에서 폼의 유효성 검사를 위한 라이브러리이다.
useForm을 가지고 간단한 폼을 만들어봤다.
import { useEffect, useState } from "react";
import { useForm } from "react-hook-form";
export default function ReactHookForm() {
const [name, setName] = useState("");
const {
watch,
register,
formState: { errors, isSubmitSuccessful },
handleSubmit,
setValue,
reset,
} = useForm({ mode: "onBlur" });
const handleChange = (e) => {
setName(e.target.value);
};
console.log(watch());
console.log(watch("username"));
const onValid = () => {
console.log("submitted");
reset({
username: "",
email: "@naver.com",
});
};
const onInvalid = (errors) => {
console.log("errors", errors);
};
return (
// 아래 블록
);
}
<form onSubmit={handleSubmit(onValid,onInvalid)}>
<input
{...register("username", {
required: "Username is required",
minLength: {
message: "The username should be longer than 5 chars",
value: 5,
},
})}
type="text"
placeholder="Username"
onChange={handleChange}
/>
<span>{errors.username?.message}</span>
<input
id="email"
type="email"
{...register("email", {
required: "Please write down your naver address",
validate: {
onlyNaver: (value) =>
value.includes("@naver.com") || "Only naver address allowed",
},
})}
placeholder="naver address"
/>
<span>{errors.email?.message}</span>
<input
type="button"
onClick={() => {
setValue("email", `${name}@naver.com`);
}}
value="Set email with username"
/>
<input type="submit" />
{isSubmitSuccessful && (
<div>
<h1>{name}, Your form is successfully submitted!</h1>
</div>
)}
</form>
register
connects inputs and state, and apply validation
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')} />
required / minLength
required, minLength를 에러 메세지와 함께 설정할 수 있다.
validate
validate를 통해 원하는 유효성 검사를 할 수 있다. (callback 함수들의 객체로 구성)
→ form에 console.log(errors.email) 를 찍어보면 다음과 같은 메세지를 확인할 수 있다.
formState
formState 객체는 전체 form의 상태에 대한 정보를 담고 있다.
const { formState: { errors, isSubmitSuccessful, isSubmitting, isDirty, touchedFields, submitCount } } = useForm<LoginForm>();
- isSubmitting
- isSubmitted: set to true after the form is submitted until the reset method is valid
- isDirty: set to true when any of the input value is modified compared to defaultValues
- dirtyFields
- touchedFields
- validationFields: fields which are getting async validation
watch
watch specified inputs and return their values
input에 입력된 값을 반환한다.
const { watch } = useForm();
console.log(watch());
console.log(watch('username'));
handleSubmit
2개의 함수를 인자로 갖는다.
onValid 함수는 form이 유효할 때 실행되고, inInvalid 함수는 form이 유효하지 않을 때 실행된다.
<form onSubmit={handleSubmit(onValid,onInvalid)}>
<input type="text" {...register("firstName")} />
<input type="text" {...register("lastName")} />
<input type="email" {...register("email")} />
<input type="submit" />
</form>
reset / resetField
rest the entire form state, fields reference, subscriptions or an individual field state
resetField("firstName")
resetField("firstName", { keepError: true })}
resetField("firstName", { keepDirty: true })}
resetField("firstName", { defaultValue: "New" })}
mode
validation이 발생하는 시점을 설정할 수 있다.
const { register } = useForm<LoginForm>({ mode: "onSubmit" });
- onSubmit
- onChange
- onBlur: input에서 벗어나 다른 곳을 클릭했을 때
- onTouched: 가장 처음 onBlur가 발생했을 때 검사하고, 이후에는 매번 ref 값이 바뀔 때마다
- all
setError
the function allows you to manually set one or more errors
export default function ReactHookForm(){
const { setError, formState: { errors }} = useForm<FormInputs>();
useEffect(() => {
setError("username", {
type: "manual",
message: "Dont Forget Your Username Should Be Cool!",
})
}, [setError]);
return(
<>
<form onSubmit={handleSubmit(onSubmit)}>
<input {...register("username")} />
{errors.username && <p>{errors.username.message}</p>}
<input type="submit" />
</form>
// 여러 에러 설정
<button
type="button"
onClick={() => {
const inputs = [
{
type: "manual",
name: "username",
message: "Double Check This",
},
{
type: "manual",
name: "firstName",
message: "Triple Check This",
},
]
inputs.forEach(({ name, type, message }) => {
setError(name, { type, message })
})
}}
>
Trigger Name Errors
</button>
</>
)
}
trigger
validation을 trigger한다.
<button type="button" onClick={()=>{trigger("lastName")}}>
Trigger
</button>
setValue
input의 register값을 특정 value로 set 해줄 때 사용한다.
기존 프로젝트에 useForm을 적용하다가 한참을 헤맨 부분이다.
'동' select 태그의 key를 districtValue로 설정하여, 다른 구를 선택했을 때 '동' select 태그가 리렌더링 되도록 했다.
이때 '동' select UI에 '동 선택'이 아니라 빈값이 나와서 로그를 찍어보니 'dong' value가 이전 '구'에 해당하는 '동'으로 되어서였다.
setValue를 통해 'dong'값을 기본값인 ''으로 설정해서 해결할 수 있었다.