📑 개요
일단... 이걸 모르고 폼 구현을 했던 나에게 깊은 애도를...............😂
이거 진짜 쓰나? 하고 포스팅 작성하기 전에 플로우 구상하고자 참고할 글들 스윽 읽어보는데
이걸 왜 안썼지 하고 글 읽는 내내 그냥 헛웃음 쳤다 ㅋㅋㅋㅋㅋㅋ
그치만... 그치만 같이 프젝했던 아이들 모두 hook form은 몰랐다구요~!!!!🥲
일단 state 나열이 없다는 것 부터가 너무나 매력적......^-^
발전하렴 과거의 나.......
🗃️ React Hook Form이란?
Form을 더 간편하게 사용하기 위해 고안된 라이브러리이다.
사용 시 폼 상태를 관리하고 유효성을 검증하는 작업이 간편해지고, 성능 최적화에 유리하다.
- React hook Form의 특징
- 비제어 컴포넌트
- state의 최소화로 인한 버그 최소화
비제어 컴포넌트이므로 setState의 사용이 기존의 폼에 비해 최소화된다. 또한 setState는 비동기로 작동하기 때문에, 이로 인한 버그를 최소화할 수 있으며 렌더링이 실시간으로 이루어지지 않으므로 성능에 이점을 줄 수 있다. - 간결한 API
직관적인 코드로 작성함으로써 form의 쉬운 관리가 가능해진다. - 유효성 검사
기본적으로 유효성 검사 로직을 내장하고 있다.
사용시에는 아래의 코드를 작성하면 된다.
npm install react-hook-form
React Hook Form을 사용한 코드와 아닌 코드의 차이가 뭐지? 하는 사람들이 있을 것이다...
난 안다. 난 개발 배운지 얼마 안됐으니까 초보들의 그 마음 너 무 잘 안 다
아직 Form에 대해 다 설명하지 않았지만, 일단 Hook을 사용한 코드와 사용하지 않은 코드를 작성해두겠다.
스킵하고 설명으로 가고 싶다면 그래도 된다.
- React Hook Form을 사용하지 않은 로그인 구현
import React, { useState } from 'react';
function LoginForm() {
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const [errors, setErrors] = useState({});
const validate = () => {
const newErrors = {};
if (!email) newErrors.email = 'Email is required';
if (!password) newErrors.password = 'Password is required';
return newErrors;
};
const handleSubmit = (event) => {
event.preventDefault();
const validationErrors = validate();
if (Object.keys(validationErrors).length > 0) {
setErrors(validationErrors);
} else {
console.log({ email, password });
// Perform login logic here
}
};
return (
<form onSubmit={handleSubmit}>
<div>
<label>Email:</label>
<input
type="email"
value={email}
onChange={(e) => setEmail(e.target.value)}
/>
{errors.email && <p>{errors.email}</p>}
</div>
<div>
<label>Password:</label>
<input
type="password"
value={password}
onChange={(e) => setPassword(e.target.value)}
/>
{errors.password && <p>{errors.password}</p>}
</div>
<button type="submit">Login</button>
</form>
);
}
export default LoginForm;
- React Hook Form을 사용한 로그인 구현
import React from 'react';
import { useForm } from 'react-hook-form';
function LoginForm() {
const { register, handleSubmit, formState: { errors } } = useForm();
const onSubmit = (data) => {
console.log(data);
// Perform login logic here
};
return (
<form onSubmit={handleSubmit(onSubmit)}>
<div>
<label>Email:</label>
<input
type="email"
{...register('email', { required: 'Email is required' })}
/>
{errors.email && <p>{errors.email.message}</p>}
</div>
<div>
<label>Password:</label>
<input
type="password"
{...register('password', { required: 'Password is required' })}
/>
{errors.password && <p>{errors.password.message}</p>}
</div>
<button type="submit">Login</button>
</form>
);
}
export default LoginForm;
💡 React Hook Form의 주요 기능
- useForm
이 훅을 통해 폼 상태와 검증을 관리한다.
const { register, handleSubmit, formState, reset, setValue, getValues, trigger, control } = useForm();
위의 예시는 가장 기본적인 형태이다.
여기서 더 깊이 들어가면 mode와 defaultValues를 사용하여 세밀한 조정을 해줄 수 있다.
- mode
폼 검증 시점을 설정한다.
- onSubmit: 폼 제출 시 검증 (기본값)
- onBlur: 폼 필드가 포커스를 잃을 때 검증
- onChange: 폼 필드의 값이 변경될 때마다 검증
- onTouched: 폼 필드가 터치(포커스 후 블러)되었을 때 검증
- all: 폼 필드의 값이 변경되거나 터치될 때마다 검증
const { register, handleSubmit, formState } = useForm({ mode: 'onChange' });
단, mode를 onChange로 설정할 경우 리렌더링이 많이 발생하여 성능 저하를 야기할 수 있다.
- defaultValues
폼의 초기 값을 설정한다. 폼이 처음 렌더링될 때 필드에 기본값을 제공할 때 사용된다. 기본값을 제공하지 않으면 초기 값은 undefined로 설정된다.
const { register, handleSubmit, reset } = useForm({
defaultValues: {
email: 'example@example.com',
password: '',
},
});
- mode와 defaultValues를 함께 사용한 예시
const { register, handleSubmit, formState: { errors, isValid }, reset, control } = useForm({
mode: 'onChange',
defaultValues: {
email: 'example@example.com',
password: '',
},
});
- register
폼 필드릉 등록하고 해당 필드의 값을 추적한다.
필드에 유효성 검사를 설정할 수도 있다.
<input
{...register('email',
{ required: 'Email is required',
pattern: /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i })} />
첫번째 매개변수에는 name을 설정하고, 두 번째 값으론 option 객체가 들어간다. (해당 코드에선 pattern)
option에는 유효성 검사에 필요한 값들이 다양하게 들어간다. (required, minLength, maxLength, pattern, validate, min, max 등)
- 다양한 option과 message를 사용한 예시 코드
<input
type="email"
{...register('email', {
required: { value: true, message: 'Email is required' },
pattern: { value: /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i, message: 'Invalid email address' }
})}
/>
- handleSubmit
폼 제출을 처리한다.
폼이 제출되면 검증을 수행하고, 유효한 경우 onSubmit 콜백을 호출한다.
const onSubmit = (data) => {
console.log(data);
};
<form onSubmit={handleSubmit(onSubmit)}>
...
</form>
- formState
폼의 상태를 나타내며 폼의 검증 상태와 에러메시지를 포함한다.
const { errors, isDirty, isSubmitting, isValid } = formState;
- 주요속성
- dirtyFields: 변경된 필드들을 나타내는 객체.
- isDirty: 하나 이상의 필드가 변경되었는지 여부를 나타내는 부울 값.
- errors: 각 필드의 오류 상태를 나타내는 객체.
- isSubmitting: 폼이 제출 중인지 여부를 나타내는 부울 값.
- isSubmitted: 폼이 한 번이라도 제출되었는지 여부를 나타내는 부울 값.
- isSubmitSuccessful: 폼 제출이 성공적으로 완료되었는지 여부를 나타내는 부울 값.
- isValid: 폼의 모든 필드가 유효한지 여부를 나타내는 부울 값.
- touchedFields: 터치된(포커스 후 블러된) 필드들을 나타내는 객체.
- submitCount: 폼이 제출된 횟수를 나타내는 숫자.
코드 예시
const {
register,
handleSubmit,
formState: { errors, isDirty, isSubmitting, isSubmitSuccessful, touchedFields, isValid },
} = useForm({ mode: 'onChange' });
...
<button type="submit" disabled={isSubmitting || !isValid}>Submit</button>
- reset
폼을 초기 상태로 리셋하며, 초기 값을 제공할 수도 있다.
reset(); // 폼을 초기 상태로 리셋
reset({ email: 'test@example.com' }); // 초기 값을 제공하여 리셋
기존 데이터를 편집할 때도 유용하게 사용이 가능하다.
useEffect(() => {
// 서버에서 사용자 데이터를 가져오는 함수
const fetchUserData = async () => {
const response = await fetch(`/api/user/${userId}`);
const data = await response.json();
reset(data); // 폼 초기값을 가져온 사용자 데이터로 설정
setLoading(false);
};
fetchUserData();
}, [userId, reset]);
- setValue, getValues
setValue는 특정 필드의 값을 설정한다.
getValues는 특정 필드 또는 전체 폼의 현재 값을 가져온다.
setValue('username', 'newUser'); // 'username' 필드의 값을 설정
const username = getValues('username'); // 'username' 필드의 현재 값을 가져옴
const values = getValues(); // 전체 폼의 현재 값을 가져옴
- trigger
특정 필드 또는 전체 폼에 대한 검증을 수동으로 트리거한다.
trigger('username'); // 'username' 필드의 검증을 트리거
trigger(); // 전체 폼의 검증을 트리거
- watch
폼 필드의 변화를 감지하고 실시간으로 값을 추적한다.
const watchedValues = watch(); // 모든 필드의 변화를 감지
const emailValue = watch('email'); // 특정 필드의 변화를 감지
const values = watch(['email', 'password']); // 여러 필드의 변화를 감지
- setError, clearErrors
setError은 특정 필드에 에러를 설정한다.
clearErrors는 특정 필드 또는 전체 폼의 에러를 제거한다.
setError('username', {
type: 'manual',
message: 'Username is already taken',
});
clearErrors('username'); // 'username' 필드의 에러를 제거
clearErrors(); // 전체 폼의 에러를 제거
✨ 마무리
헉 생각보다 길다...
검색해보니 실무에서는 꽤 쓴다는데...
나는 프로젝트를 하면서 써보질 않았다.
프로젝트에서 로그인 폼을 만들 때 유효성 검사며 상태 변화며 일일이 하는 게 너무 번거롭다 느꼈는데
그부분을 해소해주는 hook... 일단 state의 남발이 없어도 된다는 게 너무 큰 강점으로 다가왔다.
유효성 검사도 간단하게 해주고... 흑흑.
이걸 왜 이제야 알았나!
- 요약
다 읽어보자... 요약...하기엔 내용이 방대하다고 본다.
'개발 > Front' 카테고리의 다른 글
[React] Recoil 사용법과 비동기 처리 방법, Redux와의 차이점 (0) | 2024.06.11 |
---|---|
[React] React.fragment의 사용법과 사용 이유 (1) | 2024.06.09 |
[React] 제어 컴포넌트와 비제어 컴포넌트의 차이 (1) | 2024.06.09 |
[React] 메모이제이션 (1) | 2024.06.09 |
[React] HTML과 React의 이벤트 처리 차이점 (0) | 2024.04.17 |