React에서 form
의 validation
을 도와주는 라이브러리이다.
이 라이브러리는 기본적으로 uncontrolled component를 베이스로 하지만 controlled component에 대한 지원도 하고 있다.
npm i react-hook-form
// Login.js - React 내부의 간단한 로그인 폼
// 웹페이지 상태(state)관리를 위한 useState hook 불러오기
import { useState } from "react";
const Login = () => {
// 아이디와 비밀번호 state로 관리하기
const [username, setUsername] = useState("");
const [password, setPassword] = useState("");
// input 태그에서 아이디와 비밀번호 받아와, state 변경해주기
const onValidName = (event) => {
setUsername(event.target.value)
}
const onValidPassword = (event) => {
setUsername(event.target.value)
}
// 로그인 버튼 눌렀을때, 아이디와 비밀번호 state값 가져오기
const handleSubmit = (event) => {
event.preventDefault();
console.log(username, password);
}
//input 값이 바뀔때마다 state값, value값 최신화
return (
<form onSubmit={handleSubmit}>
<Input
value={username}
type="text"
placeholder="아이디"
onChange={onValidName}
/>
<Input
value={password}
type="password"
placeholder="비밀번호"
onChange={onValidPassword}
/>
<Input type="submit" value="로그인" />
</form>
);
};
export default Login;
const { register, handleSubmit } = useForm();
React-Hook-Form 은 데이터 검증을 보다 간단하게 하는 등의, input 값 관리를 쉽게 해주는 register
를 지원한다. register는 해당 컴포넌트의 값을 트래킹하고 validation을 하기위해 react hook form 라이브러리에 등록한다는 뜻이다.
input을 등록하려면 아래처럼 ref
에 register
을 넘겨주면 된다. 이 때 중요한 점은 반드시 name 필드를 넘겨줘야 하며, 이는 유니크해야된다는 것이다.
<input type="text" ref={register} name="firstName" />
handleSubmit
메서드는 form 제출을 핸들링하는 메서드이며, form 컴포넌트
의 onSubmit prop
에 넘겨주면 된다.
const onFormSubmit = data => console.log(data);
const onErrors = errors => console.error(errors);
<form onSubmit={handleSubmit(onFormSubmit, onErrors)}>
{/* ... */}
</form>
handleSubmit
은 두가지 아규먼트를 받는다.
첫번째는 폼 validation이 success
일 때 호출하는 콜백이고
두번째는 폼 validation이 fail
일 때 에러와 함께 호출되는 콜백이다.
간단한 example은 아래와 같다.
import React from "react";
import { useForm } from "react-hook-form";
export default function App() {
const { register, handleSubmit } = useForm();
const onSubmit = data => console.log(data);
return (
<form onSubmit={handleSubmit(onSubmit)}>
<input name="firstName" ref={register} />
<input name="LastName" ref={register} />
<input type="submit" />
</form>
);
}
handleSubmit() 사용, onSumit 함수에 post요청 > json 변환.
input에서 입력하는 값을 실시간으로 확인하기 위해서는 watch라는 함수를 사용할 수 있습니다.
export default function App() {
const { register, watch } = useForm();
console.log(watch());
return (
<div className="App">
<form>
<input type="text" placeholder="username" {...register("username")} />
<input type="submit" />
</form>
</div>
);
}
위의 코드를 보면 알겠지만, 기본적으로 ref를 사용하는 uncontrolled 방식이기 때문에
onChange
나value
같은 상태 값을 prop으로 넘겨줄 필요가 없어 코드가 깔끔하다.
<input
type="text"
placeholder="username"
{...register("username", {
required: "Username is required",
minLength: {
value: 5,
message: "Username must be longer than 5 characters"
}
})}
/>
여기서 에러는 Validation을 통과하지 못했다는 것을 의미합니다
validation 옵션은 register 메서드에 아규먼트로 넣어주면 된다.
validation option은 아래와 같다.
input의 required 는 필수 값 체크를 해주고, minLength 는 입력 값의 최소 길이 체크를 해준다.
<Input name="name" innerRef={register({ required: true })} />
위의 코드는 input 컴포넌트를 required하게 한 것인데 만약 아무 값도 입력하지 않고 서브밋하면 handleSubmit 메서드의 두번째 콜백이 실행된다.
<Input name="name" innerRef={register({
pattern : {
value : /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i,
errors : "이메일 형식에 맞게 입력해주세요
}
}) />
그리고 에러 오브젝트는 useForm에서 접근할 수 있다.
const { register, handleSubmit, errors } = useForm();
실시간 유효성 검사를 사용하기 위해서는 useForm을 다음과 같이 변경하여야 합니다.
useForm({ mode: "onChange" });
errors는 에러들이 담긴 객체로 현재는 모드가 onChange이기 때문에 에러가 실시간으로 업데이트 됩니다.
userForm을 다음과 같이 변경하게 되면 React Hook Form이 실시간으로 유효성 검사를 하게 됩니다. 먼저 input에 Validation을 설정한 다음에 useForm에서 errors라는 객체를 가져옵니다.
import React from "react";
import { useForm } from "react-hook-form";
import "./styles.css";
export default function App() {
const { register, handleSubmit, errors } = useForm();
const onSubmit = (data) => {
console.log(data);
};
const onError = (error) => {
console.log(error);
};
return (
<div className="App">
<form onSubmit={handleSubmit(onSubmit, onError)}>
<input
type="text"
placeholder="username"
{...register("username", {
minLength: {
value: 5,
message: "Username must be longer than 5 characters"
}
})}
/>
<input type="submit" />
</form>
{erros && <h1>{error?.username?.message}</h1>}
</div>
);
}
다음과 같이 코드를 짜면 유효성 검사를 통과하지 못할때마다 에러 메세지가 나타난다.
// react-hook-form에서 폼 만들기 위한 useForm, 폼의 전송함수를 관리하기 위한 SubmitHandler 가져오기
import { useForm, SubmitHandler } from "react-hook-form"
// 폼에 들어갈 데이터 형식 지정하기
type myForm {
name: string,
lastName?: string
}
// react App 내부에서, useForm을 사용해 폼을 만들기위한 여러가지 요소 불러오기
function App() {
// 폼을 만들기 위한 여러가지 요소 불러오기, 폼 타입 지정해주기
const { register, handleSubmit, getValues } = useForm<myForm>();
// SubmitHandler로 타입 지정해주기 ( data를 사용할 경우에만 지정 )
const onValid:SubmitHandler<myForm> = (data) => {
console.log(data)
// getValues만 사용한다면, 이미 타입이 지정되어있으므로 따로 지정해 줄 필요가 없음
const { name, firstName } = getValues();
}
return {
<div>
<form onSubmit={handleSubmit(onValid)}>
<input {...register("name")}/>
<input {...register("firstName", { required : true })/>
</form>
</div>
}
material ui 처럼 반드시 controlled component 형태로 사용하는 라이브러리들이 있는데, react hook form은 이런 컴포넌트를 지원한다. 이 경우에는 register 메서드 대신 control 이라는 객체를 사용한다.
const { register, handleSubmit, errors, control } = useForm();
또한 react hook form에서는 Controller
라는 wrapper 컴포넌트를 제공한다. 이 컴포넌트를 통해서 controlled component를 래핑
해서 react hook form과 사용할 수 있다.
아래의 예시에서 보면 register을 넘겨주듯이 대신 control을 넘겨주고, as prop으로 사용하고자 하는 controlled component를 내려준다. 그리고 그 컴포넌트의 props는 그대로 Controller에서 전달 가능하다. validation option은 rules prop으로 넘겨주면 된다.
<Controller
name="role"
control={control}
as={Select}
options={selectOptions}
defaultValue=""
rules={{ required: "Role is required" }}
/>
추천 링크
https://velog.io/@pluviabc1/React-Hook-Form-%EB%B2%A0%EC%9D%B4%EC%A7%81
Ref
https://blog.logrocket.com/the-complete-guide-to-react-hook-form/
https://react-hook-form.com/kr/get-started