React Hook Form 으로 간단하게 Form의 유효성 검사하기
❓상황
쿠팡 클론코딩 중, 로그인 및 회원가입 form 구현할때 React Hook Form을 사용했기 때문에 정리함.
📖 React Hook Form 이란?
유효성 검사, 에러 메시지 등 구현하기 복잡한 form을 React Hook Form을 이용하면 쉽고 빠르게 form 구현 가능
🐸 설치
// npm
npm install react-hook-form
// yarn
yarn add react-hook-form
// typescript는 react-hook-form에 내장되어 있다.
🗒️ useForm()
useForm 예시
useForm은 양식을 쉽게 관리할 수 있는 custom hook이고 옵션을 사용한다.
// 예시
type FormInputs = {
firstName: string;
lastName: string;
};
const { register } = useForm<FormInputs>({
mode: 'onSubmit',
reValidateMode: 'onChange',
defaultValues: {},
resolver: undefined,
context: undefined,
criteriaMode: "firstError",
shouldFocusError: true,
shouldUnregister: false,
delayError: undefined
})
🧮 useForm : props
useForm Props : mode
onChange | onBlur | onSubmit(default) | onTouched | all = 'onSubmit'
mode는 form의 유효성 검사를 어느 동작때 시행할지 설정하는 props이다.
onChange는 과도한 렌더링으로 성능의 저하때문에 비추천이고, all도 onChange가 포함되어 과도한 렌더링을 발생시키기 때문에 비추천
useForm Props : reValidateMode
reValidateMode: onChange(default) | onBlur | onSubmit = 'onChange'
form을 제출한 후(예를 들어 onSubmit 이벤트 시) 오류가 발생할때, 다시 유효성 검사할때 어느 동작에 시행할지 설정하는 props이다.
기본적으로 입력값을 입력하여 change 이벤트가 발생하면 유효성 검사를 한다.
useForm Props : defaultValues
defaultValues: Record<string, any> = {}
form의 기본값을 세팅할때 설정하는 props이다.
기본적으로 <input>태그에 defaultValue를 설정하면 <input>태그 안에 값을 가진다.그러나 useForm의 defaultValues를 사용하면, <input>태그 안에 값을 가지지 않는다.
useForm Props : resolver
resolver: (values: any, context?: object) => Promise<ResolverResult> | ResolverResult
resolver는 유효성 검사 라이브러리를 도와주는 props이다.
사실 유효성 검사할때 정규식 표현을 사용했지, 라이브러리를 사용해보지 않아서 공부할 마음이 없어졌다.
나중에 유효성 검사 라이브러리를 사용하게 된다면, 다시 공부해서 정리 해봐야겠다.
useForm Props : context
context: object
context는 유효성 검사 라이브러리인 Yup 의 context로 사용되는 props이다.
context는 resolver와 연관된 props이다. 따라서 따로 정리하지 않았다.
useForm Props : shouldUnregister
shouldUnregister: boolean = true | false(default)
form이 unmount되면 값이 사라지게 만들지, 아닐지 설정하는 props이다.
기본값은 false로 설정되어 있다.
만약 true로 설정하고, form이 unmount되면 입력되었던 값이 모조리 사라진다.
이 상태에서 submit하게 되면, 값은 없는 상태로 전달되기 된다.
useForm Props : criteriaMode
criteriaMode : firstError(default) | all
기본값인 firstError는 register로 등록된 form의 에러들 중, 첫번째 에러만 감지한다.(type)
만약 all로 설정할 경우 모든 에러를 감지한다.(types)
useForm Props : shouldFocusError
shouldFocusError: boolean = true(default) | false
유효성 검사를 시행하고 나서, 에러가 발생한 form의 focus를 시행할지 설정하는 props이다.
focus는 register를 등록한 순서(위에서 아래로) 진행된다.
useForm Props : delayError
delayError : number
에러메시지를 표시하기까지 지연시간을 설정하는 props이다.
단, 유효성 검사 통과하여 에러메시지가 사라지는 것에는 적용되지 않고, 바로 사라진다.
useForm Props : shouldUseNativeValidation
shouldUseNativeValidation: boolean = false(default) | true
브라우저의 기본 유효성 검사를 활성화시키는 props이다.
또한, :valid, :invalid와 같은 CSS 선택자를 사용하여, styling을 할 수 있다.
활성화해도 브라우저가 완벽하게 유효성검사를 하지 않기때문에, 따로 유효성검사를 하는 편이 좋은거 같다.
🐢 useForm : register
useForm() 함수에서 입력/선택(input/select) Ref 를 등록하고, React Hook Form 을 통한 유효성 검사를 적용할 수 있다.
type FormInputs = {
firstName: string;
lastName: string;
};
const { register } = useForm<FormInputs>()
const { onChange, onBlur, name, ref } = register('firstName');
<input
onChange={onChange} // assign onChange event
onBlur={onBlur} // assign onBlur event
name={name} // assign name prop
ref={ref} // assign ref prop
/>
<input {...register('firstName')} />
🧮 register : Props
useForm Props : ref
register의 props는 input의 값이 변경되는것을 감지하는 onChange, onBlur.
<input> 태그를 참조하는 ref.
<input> 태그의 이름.
들을 props로 가진다.
onChange : ChangeHandler
onChange prop to subscribe the input change event.
onBlur : ChangeHandler
onBlur prop to subscribe the input blur event.
ref : React.Ref<any>
Input reference for hook form to register.
name : string
Input's name being registered.
// 예시
const { onChange, onBlur, name, ref } = register('firstName');
<input
onChange={onChange} // assign onChange event
onBlur={onBlur} // assign onBlur event
name={name} // assign name prop
ref={ref} // assign ref prop
/>
// 간편식
<input {...register('firstName')} />
🚀 register : Options
register Options : ref
ref : React.Ref
// 예시
<input {...register("test")} />
register Options : required
required string | {
value: boolean = true | false,
message: string
}
form 입력값의 존재 유무를 확인하는 option이다.
value : true 이면, 입력값이 있어야하며, 없을 경우 error가 발생한다.
이때, error message를 설정할 수 있는데, 이는 message: 'value'를 입력하면 에러 메시지 값을 가진다.
주의사항으로는, 자바스크립트에서는 <p>태그로 감싸져서 반환되지만, 타입스크립트에서는 문자열로 반환된다.
// 예시
<input
{...register("test", {
required: 'error message' // JS only: <p>error message</p> TS only support string
})}
/>
register Options : maxLength
maxLength : {
value: number,
message: string
}
form의 최대길이를 설정하는 option이다.
설정한 최대길이를 넘어가면, error가 발생한다.
// 예시
<input
{...register("test", {
maxLength : {
value: 2,
message: 'error message' // JS only: <p>error message</p> TS only support string
}
})}
/>
register Options : minLength
minLength : {
value: number,
message: string
}
form의 최소길이를 설정하는 option이다.
form이 최소길이를 만족하지 않으면, error가 발생한다.
<input
{...register("test", {
minLength: {
value: 1,
message: 'error message' // JS only: <p>error message</p> TS only support string
}
})}
/>
register Options : max
max : {
value: number,
message: string
}
form이 숫자값을 입력받는 경우, 최댓값을 설정하는 option이다.
최댓값을 넘어가는 경우, error가 발생한다.
<input
type="number"
{...register('test', {
max: {
value: 3,
message: 'error message' // JS only: <p>error message</p> TS only support string
}
})}
/>
register Options : min
min : {
value: number,
message: string
}
form이 숫자값을 입력받는 경우, 최솟값을 설정하는 option이다.
최솟값을 넘어가는 경우, error가 발생한다.
<input
type="number"
{...register("test", {
min: {
value: 3,
message: 'error message' // JS only: <p>error message</p> TS only support string
}
})}
/>
register Options : pattern
pattern : {
value: RegExp,
message: string
}
자바스크립트 정규식을 적용시키는 option이다.
정규식에 g flag가 있는 경우에, 마지막으로 찾은 인덱스를 추적합니다.
만약 여러개의 pattern을 사용하려면, validate를 이용해야한다.
<input
{...register("test", {
pattern: {
value: /[A-Za-z]{3}/,
message: 'error message' // JS only: <p>error message</p> TS only support string
}
})}
/>
register Options : validate★(유효성 검사에 사용하는 것을 추천)
validate : Function | Object
콜백함수를 전달하여, 다른 유효성 검사에 영향을 받지않고 자체적으로 검사를 진행한다.
즉, pattern이나, required option 대신 validate를 이용하여 검사를 진행할 수 있다.
기존 옵션에서는 message 프로퍼티가 따로 있었는데, validate는 || 비트연산자를 이용하여 message를 전달한다.
<input
{...register("test", {
validate: value => value === '1' || 'error message' // JS only: <p>error message</p> TS only support string
})}
/>
// object of callback functions
<input
{...register("test1", {
validate: {
positive: v => parseInt(v) > 0 || 'should be greater than 0',
lessThanTen: v => parseInt(v) < 10 || 'should be lower than 10',
// you can do asynchronous validation as well
checkUrl: async () => await fetch() || 'error message', // JS only: <p>error message</p> TS only support string
messages: v => !v && ['test', 'test2']
}
})}
/>
register Options : disabled
disabled : boolean = false(default) | true
<input disabled /> 와 동일한 동작을 하는 option이다.
<input
{...register("test", {
disabled: true
})}
/>
register Options : onChange
onChange : (e: SyntheticEvent) => void
onChange 이벤트를 설정하는 option이다.
register('firstName', {
onChange: (e) => console.log(e)
})
register Options : onBlur
onBlur : (e: SyntheticEvent) => void
onBlur 이벤트를 설정하는 option이다.
register('firstName', {
onBlur: (e) => console.log(e)
})
register Options : value
value : any
첫 렌더링시, form 초기 입력값을 가지도록 설정하는 option이다.
defaultValues와 달리, value option을 이용하면 form에 값이 실제로 입력된다.
register('firstName', { value: 'bill' })
register Options : shouldUnregister
shouldUnregister : boolean = true(default) | false
form이 unmount되면 입력값이 유지되는지 설정하는 option이다.
만약 true로 설정과 unmount시키고 나서 submit하면, 값이 전달되지 않는다.
ture면 유지되고, false면 사라진다.
<input
{...register("test", {
shouldUnregister: true,
})}
/>
register Options : deps
deps : string | string[]
기본적으로 register로 등록된 form만들 추적한다.
useEffect의 deps와 비슷하게, 다른 register로 등록된 form을 추적할 수도 있다.
여러개의 deps를 입력하려면, 배열을 이용해야한다.
<input
{...register("test", {
deps: ['inputA', 'inputB'],
})}
/>
😮 components에 register 등록하기
일반적인 태그에는 register는 {...register}를 하면 등록이된다.
그러나, components들은 {...register}를 이용하여 등록할 수 없다.
그래서 register의 props들을 하나씩 등록해줘야한다.
// not working, because ref is not assigned
<TextInput {...register('test')} />
const firstName = register('firstName', { required: true })
<TextInput
onChange={firstName.onChange}
onBlur={firstName.onBlur}
inputRef={firstName.ref} // you can achieve the same for different ref name such as innerRef
/>
'공부 > 프론트엔드' 카테고리의 다른 글
공부 | Line Awesome 정리 (0) | 2022.07.16 |
---|---|
공부 | react-icons 정리 (0) | 2022.07.12 |
공부 | HTTP 쿠키(cookie) 알아보기 (0) | 2022.06.24 |
공부 | 구글 아이디로 로그인 구현하기(feat. React) (0) | 2022.06.17 |
공부 | 네이버 아이디로 로그인 구현하기(feat. React) (0) | 2022.06.16 |