기존에 리액트에서 form을 다룰 때 쓰던 방식
function TodoList() {
const [toDo,setToDo] = useState("");
const onChange = (event:React.FormEvent<HTMLInputElement>) => {
const {
currentTarget: {value},
} = event;
setToDo(value);
};
const onSubmit = (event:React.FormEvent<HTMLFormElement>) => {
event.preventDefault();
console.log(toDo);
};
return (
<div>
<form onSubmit={onSubmit}>
<input onChange={onChange} value={toDo} placeholder="write todo" />
<button>ADD</button>
</form>
</div>
);
};
cf) typescript
는 각각에 맞는 event type
지정해줘야함
ex. `event:React.FormEvent<HTMLInputElement>`
cf) input이 여러개면 onChange
함수도 input 개수에 맞게 만들어줘야함
코드의 비효율성 🤮
→ 이 모든 걸 한줄로 만들 수 있는 라이브러리 React Hook Form
사용하기 쉬운 유효성 검사를 통해 성능이 뛰어나고 유연하며 확장 가능한 form
import { useForm } from "react-hook-form";
const {register} = useForm();
useForm
의 register함수를 사용하자
console.log(register("toDo"));
string을 보내주면 name이 된다.
register 함수가 반환하는 모든 것들을 input에 전달한다
<input {...register("toDo")} />
input
태그 안에 register 함수를 spread
해서 넣어줄 수 있다 (ES6 문법)
form의 입력값의 변화 관찰 함수
input값의 변화를 감지해서 보여준다
<form >
<input {...register("Email")} placeholder="Email" />
<input {...register("Name")} placeholder="Name" />
<input {...register("Id")} placeholder="Id" />
<input {...register("Pw")} placeholder="Pw" />
<button>ADD</button>
</form>
이렇게 많은 input값들을 한번에 연결해서 관리할 수 있음 → 효율적!
react hook form이 모든 validation을 마쳤을 때만 호출된다
const onValid = (data:any) => {
console.log(data);
}
<form onSubmit={handleSubmit(onValid)}>
맨 위의 onSubmit
과 같은 기능이다 (하지만 더 간단함!)
<input {...register("Email")} required placeholder="Email" />
→ html의 input 속성에 required
가 존재하기 때문에 쓸 수 있음
(cf. 지원하지 않는 브라우저에서는 ❌)
<input {...register("Email", {required: true})} placeholder="Email" />
+) {required: true} 를 {}안에 넣은 이유 : 혹시나 .. 사용자가 바꿀 수 있음 ...
required 되지 않은 input창
(에러가 있는 항목)으로 커서가 자동으로 옮겨진다
<input {...register("Email", {required: true, minLength: 5})} placeholder="Email" /><input {...register("Email", {required: true})} placeholder="Email" />
validation과 에러 표시
^
문장의 시작
+
하나 또는 하나이상
/^[A-Za-z0-9._%+-]+@naver.com$/
/^[A-Za-z0-9._%+-]+@naver.com/g
{...register('Email', {
required: 'true',
pattern: /^[A-Za-z0-9._%+-]+@naver.com$/,
{...register('Email', {
required: 'true',
pattern: {
value: /^[A-Za-z0-9._%+-]+@naver.com$/,
message: 'Only naver.com allowed',
},
})}
두가지 방식 모두 가능
const { register, handleSubmit, formState:{errors} } = useForm();
<span>{errors?.Email?.message}</span>
?
: undefined여도 실행하기 (not required)
interface IForm {
Email: string;
Name: string;
Id: string;
Pw: string;
}
-> interface 작성
formState: { errors },
} = useForm<IForm>({
defaultValues: {
Email: '@naver.com',
},
-> defaultValues
: 타입 지정 및 기본값 설정
const onValid = (data: IForm) => {
if(data.Pw !== data.PwConfirm){
setError("Pw", {message: "Passwords are not same"})
}
};
-> 비밀번호 일치 확인
interface IForm {
Email: string;
Name: string;
Id: string;
Pw: string;
PwConfirm: string;
extraError?: string;
}
-> 전체 form에 대한 error
const onValid = (data: IForm) => {
if(data.Pw !== data.PwConfirm){
setError("Pw", {message: "Passwords are not same"})
}
setError("extraError", {message: "Server offline"})
};
setError("extraError", {message: "Server offline"})
<span>{errors?.extraError?.message}</span>
-> 사용자에게 표시
{shouldFocus: true}
-> 에러 뜬 곳으로 커서 이동