근 1년만에 기술 블로그 업로드 입니다!.!
오늘은 사용자로부터 데이터를 수집하는데에 큰 도움을 주는 라이브러리인
react-hook-form 에 대한 글을 작성해 보았습니다.
react-hook-form(이하 리훅폼이라 칭하겠습니다!)이 없다면, 저희는 간단한 회원가입을 구현함에 있어서도 하나하나 state를 선언하고, state를 validate하기위한 함수들, 에러를 위한 state등 너무 많은 기능들을 직접 구현해야 합니다.
또한, 귀찮은 것과 별개로 모든 값이 state로 연결되어 있기에 하나의 값이 변할때 마다 여러 자식 컴포넌트 들에서 리렌더링이 계속해서 발생하게 됩니다.
리훅폼을 공식 docs에 나와있는 여러개의 단어-문장으로 표현하자면
DX
폼을 구축할 때 개발자들에게 완벽한 경험을 제공하는 직관적이고 기능 완성된 API
HTML standard
기존 HTML 마크업을 활용하고 제약 기반의 유효성 검사 API로 폼을 유효성 검사
Super Light
React Hook Form은 어떠한 종속성도 없는 아주 작은 라이브러리임
Performance
리렌더링 횟수를 최소화하고 유효성 검사 계산을 최소화하여 더 빠른 마운팅을 제공
Adoptable
폼 상태가 본질적으로 Local이기 때문에 다른 종속성 없이 쉽게 채택할 수 있습니다.
UX
최상의 사용자 경험을 제공하고 일관된 유효성 검사 전략을 구현
이렇게 공식문서에 정리가 되어 있습니다
해당 표현들을 하나하나 까보도록 합시다!
1. DX
여러가지 congifuration 옵션을 제공합니다.
가장 많이 사용하게 되는 것은 mode / defaultValues 입니다.
mode 옵션은 validation 전략을 설정하는데 활용됩니다.
onSubmit, onChange, onBlur등의 옵션이 있습니다.
onChange로 했을때는 다수의 리렌더링이 발생할 수 있어 주의해야 합니다!
defaultValues는 form에 기본 값을 제공하고, 제공하지 않는경우 undefined로 관리가 됩니다.
또한 제공하는 API로는
useForm , useController , useFormContext , useWatch , useFormState, useFieldArray 총 6개가 있습니다. (V7 기준)
useForm
최소한의 리렌더링으로 폼을 validate해주는 커스텀 훅입니다. 폼의 유효성을 간단히 확인하고 관리할 수 있게 해줍니다.
폼 입력값 관리, 입력값 검증, 폼 제출 처리 등을 효율적으로 할 수 있습니다.
import React from 'react';
import { useForm } from 'react-hook-form';
function LoginForm() {
const {
register,
handleSubmit,
formState: { errors },
} = useForm();
const onSubmit = data => {
console.log(data);
};
return (
<form onSubmit={handleSubmit(onSubmit)}>
<div>
<label htmlFor="username">Username</label>
<input id="username" {...register('username', { required: true })} />
{errors.username && <span>This field is required</span>}
</div>
<div>
<label htmlFor="password">Password</label>
<input id="password" type="password" {...register('password', { required: true })} />
{errors.password && <span>This field is required</span>}
</div>
<button type="submit">Login</button>
</form>
);
}
export default LoginForm;
이 예시에서는 useForm을 사용하여 폼을 만들고, register 함수를 사용하여 input태그를 등록합니다.
handleSubmit은 폼 제출 시 실행할 콜백 함수를 처리하며, formState: { errors }를 통해 입력 검증 오류를 관리합니다.
onSubmit 함수에서는 폼 데이터를 콘솔에 출력합니다.
useController
useController는 react-hook-form에서 커스텀 컴포넌트와 함께 사용할 수 있는 훅입니다.
이를 통해 커스텀 입력 컴포넌트를 폼에 쉽게 통합할 수 있습니다.
import React from 'react';
import { useController } from 'react-hook-form';
const CustomInput = ({ control, name, ...rest }) => {
const {
field: { ref, ...inputProps },
fieldState: { error },
} = useController({
name,
control,
// 여기에 더 많은 설정을 추가할 수 있습니다. 예: rules: { required: true }
});
return (
<>
<input {...inputProps} {...rest} ref={ref} />
{error && <span>{error.message}</span>}
</>
);
};
export default CustomInput;
컴포넌트는 폼의 일부로서 입력값 관리, 검증, 등록 등의 기능을 수행할 수 있습니다.
Form 컴포넌트에서는 useForm 훅을 사용하여 폼을 관리하고, CustomInput 컴포넌트를 폼 필드로 사용합니다.
useFormContext
폼의 컨텍스트를 하위 컴포넌트에 전달할 때 사용하는 훅입니다. 이를 사용하면 폼의 control, handleSubmit과 같은 메소드와 상태를 폼의 모든 하위 컴포넌트와 공유할 수 있습니다. 이 방법은 폼의 데이터와 함수를 깊은 컴포넌트 트리로 전달할 때 특히 유용합니다.
import React from 'react';
import { useFormContext } from 'react-hook-form';
function NestedInput({ name }) {
const { register } = useFormContext(); // 폼 컨텍스트에서 register 함수 사용
return <input {...register(name)} />;
}
export default NestedInput;
NestedInput 컴포넌트는 useFormContext를 사용하여 이 컨텍스트에 접근하고, register 함수를 사용하여 입력 필드를 등록합니다. 이 방법을 통해, 폼의 데이터와 함수를 깊은 컴포넌트 트리로 쉽게 전달할 수 있습니다.
useWatch
특정 필드의 변경을 감시하고, 해당 필드의 값이 변경될 때마다 컴포넌트를 리렌더링하도록 하는 훅입니다. 이를 사용하면 폼 필드의 실시간 변경 사항에 반응하는 동적인 폼을 쉽게 구현할 수 있습니다.
import React from 'react';
import { useForm, useWatch, FormProvider } from 'react-hook-form';
function WatchForm() {
const formMethods = useForm();
const { control } = formMethods;
// useWatch를 사용하여 특정 필드 감시
const watchedName = useWatch({
control,
name: 'name', // 감시할 필드의 이름
});
return (
<FormProvider {...formMethods}>
<form>
<label htmlFor="name">Name:</label>
<input {...formMethods.register('name')} />
<p>{watchedName ? `Hello, ${watchedName}!` : 'Please enter your name.'}</p>
</form>
</FormProvider>
);
}
export default WatchForm;
이 예시에서 useForm을 사용하여 폼 메소드와 control 객체를 생성합니다. useWatch는 control 객체와 감시할 필드의 이름(name)을 인자로 받아, 해당 필드의 현재 값을 반환합니다. 사용자가 입력 필드에 이름을 입력할 때마다 useWatch가 해당 변경을 감지하고, 입력된 이름을 화면에 실시간으로 표시합니다.
useWatch를 사용하면 폼 필드의 값이 변경될 때마다 특정 동작을 수행하거나, 다른 UI 요소를 조건부로 렌더링하는 등의 동적인 폼 인터랙션을 쉽게 구현할 수 있습니다.
useFormState
폼의 상태(예: 유효성 검사 오류, 폼의 수정 여부, 제출 상태 등)를 구독하는 데 사용하는 훅입니다. 이를 통해 폼의 현재 상태에 따라 UI를 동적으로 업데이트하거나, 특정 조건에서만 버튼을 활성화하는 등의 로직을 구현할 수 있습니다.
import React from 'react';
import { useForm, useFormState } from 'react-hook-form';
function FormStateExample() {
const { register, handleSubmit, control } = useForm({
defaultValues: {
email: '',
}
});
// useFormState를 사용하여 폼의 상태를 구독
const { errors } = useFormState({ control });
const onSubmit = data => console.log(data);
return (
<form onSubmit={handleSubmit(onSubmit)}>
<div>
<label htmlFor="email">Email:</label>
<input
id="email"
{...register('email', { required: 'Email is required', pattern: { value: /^\S+@\S+$/i, message: 'Invalid email format' } })}
/>
{/* 오류 메시지 표시 */}
{errors.email && <p>{errors.email.message}</p>}
</div>
<button type="submit">Submit</button>
</form>
);
}
export default FormStateExample;
이 예시에서 useForm을 사용하여 폼을 초기화하고, register 함수를 사용하여 email 필드를 등록합니다. email 필드에는 두 가지 유효성 검사 규칙이 적용됩니다: 필수 입력 필드이며, 유효한 이메일 형식을 가져야 합니다.
useFormState 훅은 control 객체를 인자로 받아 폼의 상태를 구독합니다. 이 예시에서는 errors 객체를 구조 분해 할당하여 사용하고 있으며, 이를 통해 email 필드의 유효성 검사 오류 메시지를 사용자에게 표시합니다.
useFormState를 사용하면 폼의 다양한 상태(예: isDirty, isValid, isSubmitting 등)를 쉽게 관리하고, 이를 기반으로 사용자 인터페이스를 동적으로 조정할 수 있습니다.
useWatch랑 헷갈릴 수도 있는데,
쉽게 생각하여 useFormState는 폼의 전체 상태(예: errors, isDirty, isValid, isSubmitting 등)를 구독하는 데 사용되고, 주로 폼의 유효성 상태, 변경 여부, 제출 상태 등 폼 전체의 상태 정보가 필요할 때 사용됩니다.
useWatch는 하나 또는 여러 필드의 값 변화를 구독할 때 사용하며, 특정 필드의 값에 따라 동적으로 UI를 업데이트하거나 로직을 실행할 때 적합합니다.
useFieldArray
useFieldArray는 react-hook-form에서 동적인 필드 배열을 관리할 때 사용하는 훅입니다. 이를 사용하면 폼 내에서 필드 목록을 동적으로 추가, 삭제, 업데이트할 수 있습니다. 예를 들어, 사용자가 입력할 수 있는 여러 주소나 전화번호 목록과 같은 반복되는 폼 필드를 관리할 때 유용합니다.
import React from 'react';
import { useForm, useFieldArray } from 'react-hook-form';
function HobbiesForm() {
const { register, control, handleSubmit } = useForm({
defaultValues: {
hobbies: [{ hobby: "" }]
}
});
const { fields, append, remove } = useFieldArray({
control,
name: "hobbies" // 폼 내에서 관리할 필드 배열의 이름
});
const onSubmit = data => console.log(data);
return (
<form onSubmit={handleSubmit(onSubmit)}>
<ul>
{fields.map((field, index) => (
<li key={field.id}>
<input
{...register(`hobbies.${index}.hobby`)}
/>
<button type="button" onClick={() => remove(index)}>Remove</button>
</li>
))}
</ul>
<button type="button" onClick={() => append({ hobby: "" })}>Add Hobby</button>
<button type="submit">Submit</button>
</form>
);
}
export default HobbiesForm;
폼 내에서 동적으로 필드 목록을 관리하는 복잡한 로직을 간단하게 처리할 수 있습니다.
2. HTML standard
리훅폼은 React 컴포넌트를 사용하여 폼을 구성하지만, 기본적으로 기존 HTML 폼 요소(<form>, <input>, <select>, <textarea> 등)를 사용합니다.
이는 개발자가 이미 익숙한 HTML 폼 마크업을 그대로 사용할 수 있게 하며, 폼 요소의 기본 동작을 그대로 유지합니다. 예를 들어, <input type="text">나 <select>와 같은 폼 요소를 사용하여 데이터를 수집하고, react-hook-form의 훅과 함수를 사용하여 이 데이터를 쉽게 관리할 수 있습니다.
또한 HTML5는 폼 필드에 대한 유효성 검사를 위한 여러 속성을 제공합니다. 예를 들어, required, minLength, maxLength, pattern 등의 속성을 사용하여 입력 필드에 대한 유효성 검사 규칙을 정의할 수 있습니다. react-hook-form은 이러한 HTML5 유효성 검사 API를 활용하여 폼 데이터의 유효성을 검사합니다.
리훅폼 에서는 register 함수를 사용하여 폼 필드를 등록하고, 이때 유효성 검사 규칙을 함께 정의할 수 있습니다. 예를 들어, 이메일 입력 필드에 required와 pattern을 적용하여 유효한 이메일 주소만 받아들이도록 설정할 수 있습니다.
const { register } = useForm();
<input {...register("email", { required: true, pattern: /^\S+@\S+$/i })} />
3. Supre Light
추가적인 종속성 없이 브라우저의 html폼 요소를 이용하고, 내부적으로 효율적인 상태 관리 로직을 사용하여 불필요한 리렌더링을 최소화합니다. 폼 필드의 상태가 변경될 때마다 전체 폼을 리렌더링하지 않고, 실제로 변경이 필요한 부분만 업데이트합니다. 이는 성능을 최적화하고 라이브러리의 크기를 줄이는 데 기여합니다.
또한 다른 외부 라이브러리에 의존하지 않고, 순수한 JavaScript와 React의 기능만을 사용하여 구현되었습니다. 이는 라이브러리가 추가적인 종속성 없이 독립적으로 작동할 수 있게 하며, 결과적으로 라이브러리의 크기를 작게 유지합니다.
4. Performance
리렌더링과 유효성 검사 계산을 최소화하여 빠른 마운팅을 제공할 수 있는 이유는 리훅폼의 설계 철학과 구현 방식에 기반합니다
- 비제어 컴포넌트 사용
리훅폼은 주로 비제어 컴포넌트(uncontrolled components)를 사용합니다. 비제어 컴포넌트는 React 외부에서 폼 데이터를 관리하며, 이는 React 상태 업데이트와 관련된 리렌더링을 최소화합니다. 폼 필드의 값이 변경되어도, 모든 컴포넌트를 리렌더링하지 않고 필요한 부분만 업데이트할 수 있습니다. 이 접근 방식은 특히 대규모 폼에서 성능 이점을 제공합니다.
- 이벤트 기반 유효성 검사
필드 값의 변경이나 폼 제출 시점에만 유효성 검사를 수행합니다. 이는 모든 입력에 대해 지속적으로 유효성 검사를 수행하는 대신, 필요할 때만 유효성 검사 로직을 실행하여 계산 비용을 최소화합니다. 또한, 유효성 검사 규칙은 HTML5 유효성 검사 API를 활용하여 구현되므로, 추가적인 유효성 검사 라이브러리에 대한 의존성 없이 효율적으로 작동합니다.
- 폼 상태의 로컬 관리
폼의 상태를 로컬에서 관리합니다. 이는 폼의 상태를 전역 상태 관리 라이브러리에 의존하지 않고, 폼 내부에서 독립적으로 관리함을 의미합니다. 폼 상태의 로컬 관리는 상태 업데이트 로직을 간소화하고, 폼과 관련된 리렌더링을 최소화하는 데 도움이 됩니다.
5. Adoptable
리훅폼은 폼 상태를 각 폼 인스턴스 내부에서 독립적으로 관리합니다. 이는 폼을 구현할 때 별도의 상태 관리 라이브러리(예: Redux, MobX 등)에 의존하지 않아도 된다는 것을 의미합니다. 폼의 상태와 로직이 자체적으로 캡슐화되어 있기 때문에, 기존 프로젝트에 쉽게 통합하고 사용할 수 있습니다.
6. UX
위에서 말 한 내용을 총합하여 (간단한 유효성 검사 , 간소화된 폼 상태관리 , 확장성 등), 리훅폼은 최고의 사용자 경험을 제공합니다.
다음 글에서는 이 리훅폼을 어떻게 쓰면 더 좋을지, 심화적인 내용을 다뤄보도록 하겠습니다!
'웹' 카테고리의 다른 글
Javascript 의 객체 리터럴 / 관련 팁 들 (0) | 2024.04.16 |
---|---|
React-Hook-Form 심화 watch / useWatch / controll / register / wizard form (0) | 2024.04.11 |
CRA , VITE 에서 .env 파일 사용하기 (0) | 2023.03.23 |
Vite 첫 사용 후기 (0) | 2023.03.20 |
Next.js ReWrite사용법 (0) | 2023.03.11 |