form으로 많은 입력값을 받을때 유용하게 활용할 수 있는 라이브러리다.
react에서 useState로 입력값을 받는 코드
import React, { useState } from 'react';
...
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 shorter');
}
console.log('submit');
};
return (
<div>
<form onSubmit={onSubmit}>
<input onChange={onChange} value={toDo} placeholder="write a todo" />
<button>Add</button>
{toDoError !== '' ? toDoError : null}
</form>
</div>
);
input박스마다 state, 에러 state를 모두 작성한다. 게다가 만약 회원가입 화면과 같이 input값이 많아진다면 validation도 필요하다.
그렇게 된다면 코드가 너무 길어지는데 react-hook-form을 사용하면 input이 증가하더라도 그에 따라 state를 늘려갈 필요가 없다.
npm install react-hook-form
import { useForm } from 'react-hook-form';
...
function ToDoList() {
const { register, watch } = useForm();
console.log(register('todo'));
console.log(watch());
return (
<div>
<form>
<input {...register('todo')} placeholder="write a todo" />
//input에 prop이 todo인 register가 반환하는 객체를 넣는다.
<input {...register('email')} placeholder="Email" />
<input {...register('firstName')} placeholder="Email" />
<input {...register('lastName')} placeholder="Email" />
<input {...register('password')} placeholder="Email" />
<input {...register('passwordConfirm')} placeholder="Email" />
<button>Add</button>
</form>
</div>
);
}
react-hook-form의 register 함수는 앞의 onChange이벤트 핸들러, onChange 이벤트를 대신한다.
register함수는 onBlur, onChange, ref, name 이 있다.
watch 함수는 모든 value를 출력한다.
console.log(watch())를 작성하면 {todo : '... '}으로 입력된 데이터 값이 실시간으로 출력된다.
이 코드는 입력값이 많을때 유용하다. input 태그가 많아지면 보통 그에 따라 state 가 증가하는데 hook form을 사용하면 기존의
const { register, watch } = useForm(); 만으로 해결할 수 있다.
https://react-hook-form.com/api/useform/register#main
https://react-hook-form.com/api/useform/watch#main
handleSubmit은 두개의 인자를 받는다.
https://react-hook-form.com/api/useform/handlesubmit/
그림의 설명과 같이 submitHandler는 데이터가 유효할때 호출되는 함수, SubmitErrorHandleer는 데이터가 유효하지 않을때 호출되는 함수다.
function TodoList() {
const { register, handleSubmit } = useForm();
const onValid = (data: any) => {
console.log(data);
};
return (
<div>
<form onSubmit={handleSubmit(onValid)}>
<input {...register("todo")} placeholder="write todo" />
<input {...register("email")} placeholder="email" />
<input {...register("name")} placeholder="name" />
<button>Add</button>
</form>
</div>
);
}
이때 input 태그 안에 required:true를 추가하면 그 태그의 데이터가 필수값이 돼서 데이터가 입력되지않으면 submit되지않는다.
<input {...register("todo")} required={true} placeholder="write todo" />
위의 코드와 같이 required 속성을 태그에 넣을 수도 있지만
<input
{...register("todo", { required: true })}
placeholder="write todo"
/>
required 속성을 register 함수 내부에 넣어주면 자바스크립트에서 validation을 해서 required 속성을 지원하지 않는 브라우저나 모바일에서도 동작 가능하다. 그리고 html을 수정해서 required 속성을 지우고 데이터를 등록하는 걸 막을 수 있다.
또 다른 장점은 required:true인 input box가 값이 빈채로 submit을 하면 빈 input box로 커서를 옮겨준다.
required 뿐만아니라 min, max, minLength 등 속성을 추가해서 validation이 가능하다.
+) useForm의 setError함수를 사용해 조건에 맞지 않을 때 에러를 출력할 수도 있고
onValid는 interface IForm을 받아서 데이터 타입검사를 할 수 있다.
const {
register,
handleSubmit,
formState: { errors },
setError,
} = useForm<IForm>({
defaultValues: {
email: '@naver.com',
},
});
interface IForm {
email: string;
firstName: string;
lastName: string;
username?: string;
password: string;
passwordConfirm: string;
}
const onValid = (data: IForm) => {
if (data.password !== data.passwordConfirm) {
setError(
'password',
{ message: 'password are not the same' },
{ shouldFocus: true }
);
}
};
password와 passwordConfirm이 같은 값이 아닐 경우
이런 경고가 뜬다
const { register, handleSubmit, formState } = useForm();
console.log(formState.errors);
return (
<div>
<form onSubmit={handleSubmit(onValid)}>
<input
{...register("todo", { required: true, minLength: 10 })}
placeholder="write todo"
/>
<button>Add</button>
</form>
</div>
);
}
위의 코드에 formState를 추가하면 input box에 입력한 데이터가 필수조건에 맞지 않을때 오류를 출력한다.
<input
{...register("todo", {
required: true,
minLength: { value: 10, message: "your input is too short" },
})}
placeholder="write todo"
/>
또 input box 속성을 이런식으로 작성해서 오류가 발생하면 메세지까지 띄워줄 수 있다.
<input
{...register('firstName', {
required: true,
validate: {
noOatmeal: (value) =>
value.includes('oatmeal') ? 'NO oatmeals allowed' : true,
noNick: (value) =>
value.includes('nick') ? 'NO Nicks allowed' : true,
},
})}
placeholder="firstName"
/>
inputbox의 register 함수에 validate 속성을 넣는다. 위와 같이 한개 이상의 validation조건을 넣을 수 있다.