
많은 form들을 관리해야 할 때 → useState, onChange 핸들러 남발하면서 가독성이 떨어지는 것을 방지form validation을 하는데 시간을 절약하고 싶을 때rerender을 피하려 할 때function ToDoList() {
const [toDo, setToDo] = useState("");
const [toDoError, setToDoError] = useState("");
const onChange = (event: React.FormEvent<HTMLInputElement>) => {
const {
currentTarget: { value },
} = event;
setToDoError("");
setToDo(value);
};
const onSubmit = (event: React.FormEvent<HTMLFormElement>) => {
event.preventDefault();
if (toDo.length < 10) {
return setToDoError("To do should be longer");
}
console.log("submit");
};
return (
<div>
<form onSubmit={onSubmit}>
<input onChange={onChange} value={toDo} placeholder="Write a to do" />
<button>Add</button>
{toDoError !== "" ? toDoError : null}
</form>
</div>
);
}
npm install react-hook-form
or
yarn install react-hook-form
import { useForm } from "react-hook-form";
function ToDoList(){
const { register, handleSubmit } = useForm<IForm>();
const onValid = (data: IForm) => {
console.log(data) // form 에 입력한 data들이 출력됨. (email)
}
return (
<div>
<form onSubmit={handleSubmit(onValid)}>
<input {...register("email")} />
<button>등록</button>
</form>
</div>
);
}
handleSubmit 함수를 사용할 때는 첫번째 매개변수로 데이터가 유효할 때 호출되는 다른 함수를 받는다. const { register, handleSubmit, formState: { errors } } = useForm<IForm>();
<form onSubmit={handleSubmit(onValid)}>
<input
{...register("email", {
required: "Email is required",
})}
placeholder="Email"
/>
<span>{errors?.email?.message}</span> // 이메일을 입력 하지 않았을 때 "Email is required"가 표시된다.
<button>등록</button>
</form>
naver.com만 받아야 하는 상황이 있을 수도 있다. const { register, handleSubmit, formState: { errors } } = useForm<IForm>();
<form onSubmit={handleSubmit(onValid)}>
<input
{...register("email", {
required: "Email is required",
pattern: {
value: /^[A-Za-z0-9._%+-]+@naver.com$/,
message: "Only naver.com emails allowed",
},
})}
placeholder="Email"
/>
<span>{errors?.email?.message}</span> // naver.com 으로 이메일이 끝나지 않는다면, 메시지가 출력된다.
<button>등록</button>
</form>
<input
{...register("password1", {
required: "Password is required",
minLength: {
value: 5,
message: "Your password is too short.",
},
})}
placeholder="Password1"
/>
const { register, handleSubmit, formState: { errors }, setError } = useForm<IForm>();
const onValid = (data: IForm) => {
if (data.password !== data.password1) {
setError(
"password1",
{ message: "Password are not the same" },
{ shouldFocus: true }
);
}
};
const emailCheck = async () => {
const email = watch("email"); // 폼의 email 필드의 값을 가져온다.
await axios
.get(`${process.env.NEXT_PUBLIC_API_URL}/api/users/exists`, {
params: {
email: email,
},
})
.then((res) => {
// 이메일이 중복이면,
if (res.data) {
setError("email", {
message: "* 이미 가입된 이메일입니다.",
});
} else {
setError("email", {
message: "* 가입 가능한 이메일입니다.",
});
}
});
};
return (
<RegisterForm onSubmit={handleSubmit(onVaild)}>
<RegisterLabel>
이메일 <ErrMsg>{errors?.email?.message}</ErrMsg>
</RegisterLabel>
<EmailContainer>
<Input
style={{ width: "300px" }}
{...register("email", {
required: "* 필수 입력",
})}
type="email"
placeholder="user@email.com"
/>
<EmailCheckBtn onClick={emailCheck}>중복 확인</EmailCheckBtn>
);
const {
register,
handleSubmit,
formState: { errors },
setError,
} = useForm<IForm>({
defaultValues: {
email: "@naver.com",
},
});


<ModalContainer>
<Title>장치 등록</Title>
<XBtn onClick={closeModal} />
<FormContainer>
<InputForm onSubmit={handleSubmit(onVaild)}>
<InputLabel>
시리얼 넘버(S/N) <ErrorMsg>{errors?.serial?.message}</ErrorMsg>
</InputLabel>
<Input
{...register("serial", {
required: "* 입력해주세요",
})}
placeholder="R2U-B00-0000"
/>
<InputLabel>
카테고리 <ErrorMsg>{errors?.category?.message}</ErrorMsg>
</InputLabel>
<Select {...register("category")}>
{categoryList?.map((category) => {
return (
<Option key={category.categoryName}>
{category.categoryName}
</Option>
);
})}
</Select>
<InputLabel>장치 타입</InputLabel>
<Select {...register("type")}>
<Option>RTAP2U</Option>
<Option>RTK2U</Option>
</Select>
<InputLabel>
장치 이름 <ErrorMsg>{errors?.name?.message}</ErrorMsg>
</InputLabel>
<Input
{...register("name", {
required: "* 입력해주세요",
})}
placeholder="100번 버스"
/>
<InputLabel>메모 (선택)</InputLabel>
<Input {...register("info")} placeholder="테스트용 디바이스" />
<Btn>등록</Btn>
</InputForm>
</FormContainer>
</ModalContainer>
input 태그에서만 react-hook-form을 사용하는 것이 아닌 select 태그에서도 사용하였다.handleSubmit으로 전달한 함수인 onSubmit 에서 장치 등록 mutation을 호출한다. const onVaild = (formData) => {
addDeviceMutation.mutate({ formData, accessToken });
};
// addDeviceMutation
const addDeviceMutation = useMutation(addDevice, {
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ["devices"] });
SaveAlert(); // 저장완료 Alert
reset(); // useForm 초기화
closeModal();
},
onError: () => {
WarningAlert(2);
},
});
reset({
data: "test",
})
출처 : 노마드코더 마스터클래스