
https://www.npmjs.com/package/react-hook-form
react-hook-form
Performant, flexible and extensible forms library for React Hooks. Latest version: 7.53.0, last published: 19 days ago. Start using react-hook-form in your project by running `npm i react-hook-form`. There are 5111 other projects in the npm registry using
www.npmjs.com
https://ko.legacy.reactjs.org/docs/forms.html#controlled-components
ํผ – React
A JavaScript library for building user interfaces
ko.legacy.reactjs.org
react hook form ์ด๋?
react hook form ๋ ์ ํจ์ฑ ๊ฒ์ฌ๋ฅผ ์ฝ๊ฒ ํ ์ ์๋ form์ ์ ๊ณตํ๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ด๋ค.
react hook form ์ ์ฌ์ฉํ๋ ์ด์ ?
1. ์ฑ๋ฅ
Formik์ด๋ Redux Form๋ณด๋ค ์๋๊ฐ ํจ์ฌ ๋น ๋ฅด๋ค
https://github.com/react-hook-form/performance-compare
2. ์์ค์ฝ๋๊ฐ ๊น๋
3. ๋น์ ์ด ์ปดํฌ๋ํธ ๋ฐฉ์์ ์ฌ์ฉ์ผ๋ก ๋ถํ์ํ ๋ ๋๋ง์ ๋ง์์ฃผ์ด ์๋๊ฐ ๋น ๋ฅด๋ค.
์ ์ด ์ปดํฌ๋ํธ vs ๋น์ ์ด ์ปดํฌ๋ํธ
์ ์ด ์ปดํฌ๋ํธ
HTML์์ <input>, <textarea>, <select>์ ๊ฐ์ ํผ ์๋ฆฌ๋จผํธ๋ ์ผ๋ฐ์ ์ผ๋ก ์ฌ์ฉ์์ ์ ๋ ฅ์ ๊ธฐ๋ฐ์ผ๋ก ์์ ์ state๋ฅผ ๊ด๋ฆฌํ๊ณ ์ ๋ฐ์ดํธํฉ๋๋ค. React์์๋ ๋ณ๊ฒฝํ ์ ์๋ state๊ฐ ์ผ๋ฐ์ ์ผ๋ก ์ปดํฌ๋ํธ์ state ์์ฑ์ ์ ์ง๋๋ฉฐ setState()์ ์ํด ์ ๋ฐ์ดํธ๋ฉ๋๋ค.
์ฐ๋ฆฌ๋ React state๋ฅผ “์ ๋ขฐ ๊ฐ๋ฅํ ๋จ์ผ ์ถ์ฒ (single source of truth)“๋ก ๋ง๋ค์ด ๋ ์์๋ฅผ ๊ฒฐํฉํ ์ ์์ต๋๋ค. ๊ทธ๋ฌ๋ฉด ํผ์ ๋ ๋๋งํ๋ React ์ปดํฌ๋ํธ๋ ํผ์ ๋ฐ์ํ๋ ์ฌ์ฉ์ ์ ๋ ฅ๊ฐ์ ์ ์ดํฉ๋๋ค. ์ด๋ฌํ ๋ฐฉ์์ผ๋ก React์ ์ํด ๊ฐ์ด ์ ์ด๋๋ ์ ๋ ฅ ํผ ์๋ฆฌ๋จผํธ๋ฅผ “์ ์ด ์ปดํฌ๋ํธ (controlled component)“๋ผ๊ณ ํฉ๋๋ค.
์ถ์ฒ -https://ko.legacy.reactjs.org/docs/forms.html#controlled-components
function ControlledComponent() {
const [inputValue, setInputValue] = useState('');
const handleChange = (e) => {
setInputValue(e.target.value);
};
return (
<input type="text" value={inputValue} onChange={handleChange} />
);
}
์ ์ด ์ปดํฌ๋ํธ๋ React ์ปดํฌ๋ํธ์ **์ํ(state)**๊ฐ ์ ๋ ฅ ํ๋์ ๊ฐ(value)์ ๊ด๋ฆฌํ๋ ๋ฐฉ์์ด๋ค.
์ ๋ ฅ ํ๋์ ๊ฐ์ ํญ์ React ์ํ์ ์ํด "์ ์ด"๋๋ค.
- ์ํ๋ก ๊ฐ ๊ด๋ฆฌ: ์ฌ์ฉ์๊ฐ ์ ๋ ฅ ํ๋์ ๋ฌด์ธ๊ฐ๋ฅผ ์ ๋ ฅํ๋ฉด, onChange ์ด๋ฒคํธ๊ฐ ๋ฐ์ํ๊ณ ์ด๋ฅผ ํตํด ์ํ๊ฐ ์ ๋ฐ์ดํธ๋ฉ๋๋ค.
- ์ค์๊ฐ ๊ฐ ๋ฐ์: ์ํ๊ฐ ์ ๋ฐ์ดํธ๋๋ฉด ์ฆ์ ์ ๋ ฅ ํ๋์ ๊ฐ์ด ๋ณ๊ฒฝ๋ฉ๋๋ค
์ด๋ฌํ ๋ฐฉ์์ผ๋ก ๋ฐ์ดํฐ๋ฅผ ์ ๋ถ ๋ฐ์์ฌ ์ ์์ด ์ ํจ์ฑ ๊ฒ์ฌ์ ํ์ํ๋ฐ
๋ฐ์ดํฐ๋ฅผ ํ๋ํ๋ ๋ค ๋ฐ์์ค๋ฏ๋ก ๋นํจ์จ์ ์ด๊ฑฐ๋ ์๋๊ฐ ๋๋ฆด ์ ์๋ ๋จ์ ์ด ์๋ค
๋น์ ์ด ์ปดํฌ๋ํธ
๋๋ถ๋ถ ๊ฒฝ์ฐ์ ํผ์ ๊ตฌํํ๋๋ฐ ์ ์ด ์ปดํฌ๋ํธ๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ด ์ข์ต๋๋ค. ์ ์ด ์ปดํฌ๋ํธ์์ ํผ ๋ฐ์ดํฐ๋ React ์ปดํฌ๋ํธ์์ ๋ค๋ฃจ์ด์ง๋๋ค. ๋์์ธ ๋น์ ์ด ์ปดํฌ๋ํธ๋ DOM ์์ฒด์์ ํผ ๋ฐ์ดํฐ๊ฐ ๋ค๋ฃจ์ด์ง๋๋ค.
๋ชจ๋ state ์ ๋ฐ์ดํธ์ ๋ํ ์ด๋ฒคํธ ํธ๋ค๋ฌ๋ฅผ ์์ฑํ๋ ๋์ ๋น์ ์ด ์ปดํฌ๋ํธ๋ฅผ ๋ง๋ค๋ ค๋ฉด ref๋ฅผ ์ฌ์ฉํ์ฌ DOM์์ ํผ ๊ฐ์ ๊ฐ์ ธ์ฌ ์ ์์ต๋๋ค.
์ถ์ฒ - https://ko.legacy.reactjs.org/docs/uncontrolled-components.html
๋น์ ์ด ์ปดํฌ๋ํธ๋ ์ ๋ ฅ ํ๋์ ๊ฐ์ด React ์ํ๊ฐ ์๋ DOM ์์ฒด์์ ๊ด๋ฆฌ๋๋ ๋ฐฉ์์ ๋๋ค. ์ฆ, ์ ๋ ฅ ํ๋์ ๊ฐ์ React ์ํ์ ๋ ๋ฆฝ์ ์ผ๋ก ๊ด๋ฆฌ๋๋ค.
ํน์ง:
- ์ฐธ์กฐ๋ก ๊ฐ ๊ด๋ฆฌ: React์์๋ ref๋ฅผ ์ฌ์ฉํด ์ง์ DOM์ ์ ๊ทผํ๊ณ , ์ ๋ ฅ ํ๋์ ๊ฐ์ ์ฐธ์กฐํ ์ ์์ต๋๋ค.
- ๊ฐ์ ์ฐธ์กฐํ ๋๋ง: ์ ๋ ฅ ํ๋์ ๊ฐ์ ํ์ธํ๊ฑฐ๋ ๋ณ๊ฒฝํ ๋๋ง DOM์ ์ ๊ทผํฉ๋๋ค.
ref๋ ๊ฐ์ ์ ๋ฐ์ดํธ ํ์ฌ๋ ๋ฆฌ๋๋๋ง ๋์ง ์๋ ํน์ฑ์ผ๋ก, ์ ๋ ฅ์ด ๋ชจ๋ ๋๊ณ ๋ ํ ref๋ฅผ ํตํด ๊ฐ์ ํ๋ฒ์ ๊ฐ์ ธ์์ ํ์ฉํ๋ค.
function UncontrolledComponent() {
const inputRef = useRef(null);
const handleSubmit = (e) => {
e.preventDefault();
console.log(inputRef.current.value); // DOM์์ ์ง์ ๊ฐ ์ ๊ทผ
};
return (
<form onSubmit={handleSubmit}>
<input type="text" ref={inputRef} />
<button type="submit">Submit</button>
</form>
);
}
react-hook-form ์์ํ๊ธฐ
npm install react-hook-form
react-hook-form ์ฃผ์๊ฐ๋
1. useForm
useForm์ React Hook Form์ ํต์ฌ ํจ์๋ก, ํผ์ ์ธ์คํด์ค๋ฅผ ์์ฑํ๊ณ ํผ ๋ฐ์ดํฐ์ ๋ฉ์๋๋ฅผ ์ ๊ณตํ๋ค.
2. register
register๋ ์ ๋ ฅ ํ๋๋ฅผ react- hook-form์ ๋ฑ๋กํ๋ ํจ์์ด๋ค.
์ด๋ฅผ ํตํด ํด๋น ์ ๋ ฅํ๋์ ๊ฐ์ด ํผ์ ์ฐ๊ฒฐ๋๊ณ , ๊ฐ์ ์ฝ๊ฒ ์ถ์ ๊ฐ๋ฅํ๋ค.
register์ ์ต์ ์ ์ถ๊ฐํ์ฌ ๊ฒ์ฆ(validation) ๊ท์น์ ์ค์ ํ ์ ์๋ค.
import { useForm } from "react-hook-form";
function MyForm() {
const { register, handleSubmit } = useForm();
const onSubmit = (data) => {
console.log(data); // ์
๋ ฅ ๋ฐ์ดํฐ ์ถ๋ ฅ
};
return (
<form onSubmit={handleSubmit(onSubmit)}>
<input {...register("name")} /> {/* 'name' ํ๋๋ฅผ ๋ฑ๋ก */}
<input {...register("age")} />
<button type="submit">Submit</button>
</form>
);
}
3.handleSubmit
handleSubmit์ ํผ ์ ์ถ์ ์ฒ๋ฆฌํ๋ ํจ์์ด๋ค.
ํผ์ด ์ ์ถ๋ ๋ ์ ๋ ฅ๋ ๋ฐ์ดํฐ๊ฐ ๊ฒ์ ๋๋ฉฐ,์ ํจํ ๊ฒฝ์ฐ์๋ง ์ฝ๋ฐฑ ํจ์๊ฐ ํธ์ถ๋๋ค.
<form onSubmit={handleSubmit(onSubmit)}>
{/* ํผ ์ ์ถ ์ onSubmit ํจ์๊ฐ ํธ์ถ๋จ */}
</form>
4.errors
errors๋ ํผ ๊ฒ์ฆ ์ค ๋ฐ์ํ ์๋ฌ๋ฅผ ์ถํ๊ณ , ์ด๋ค ์ ๋ ฅ ํ๋์์ ์๋ฌ๊ฐ ๋ฐ์ํ๋์ง๋ฅผ ๋ณด์ฌ์ค๋ค.
์ด๋ฅผ ์ฌ์ฉํ์ฌ ๊ฐ ์ ๋ ฅ ํ๋์ ๋ํด ๋ฐ์ํ ์๋ฌ๋ฅผ errors๋ฅผ ํตํด ํ์ธํ๊ณ ์๋ฌ ๋ฉ์์ง ์ฒ๋ฆฌ๊ฐ ๊ฐ๋ฅํ๋ค.
function MyForm() {
const { register, handleSubmit, formState: { errors } } = useForm();
return (
<form onSubmit={handleSubmit(onSubmit)}>
<input {...register("name", { required: true })} />
{errors.name && <p>Name is required</p>}
<button type="submit">Submit</button>
</form>
);
}
5.formState
formState๋ ํผ์ ์ํ๋ฅผ ์ถ์ ํ๋ ๊ฐ์ฒด๋ก, ํผ์ด ํ์ฌ ์ ํจํ์ง ๋ณ๊ฒฝ๋์๋์ง, ์ ์ถ ์๋ ์ฌ๋ถ ๋ฑ์ ์ถ์ ํ ์ ์๋ค.
- isValid : ํผ์ด ์ ํจํ์ง ์ฌ๋ถ
- isDirty : ํ๋ ์ด์์ ์ ๋ ฅ ํ๋ ๊ฐ์ด ๋ณ๊ฒฝ๋์๋์ง ์ฌ๋ถ
- isSubmitting : ํผ์ด ์ ์ถ ์ค์ธ์ง ์ฌ๋ถ.
const { register, handleSubmit, formState: { isValid, isDirty } } = useForm();
6.reset
reset์ ํผ์ ๊ฐ์ ์ด๊ธฐํํ๋ ํจ์์ด๋ค.
์ด๋ฅผ ์ฌ์ฉํ๋ฉด ์ ์ถ ํ ํผ์ ๋น์ฐ๊ฑฐ๋ ํน์ ์ํ๋ก ๋ฆฌ์ ๊ฐ๋ฅํ๋ค.
const { register, handleSubmit, reset } = useForm();
const onSubmit = (data) => {
console.log(data);
reset(); // ํผ ์ด๊ธฐํ
};
return (
<form onSubmit={handleSubmit(onSubmit)}>
<input {...register("name")} />
<button type="submit">Submit</button>
</form>
);
7.watch
watch๋ ํน์ ์ ๋ ฅ ํ๋์ ๊ฐ์ ์ค์๊ฐ์ผ๋ก ์ถ์ ํ ์ ์๋ ํจ์์ด๋ค.
์ ๋ ฅ ํ๋์ ๋ณ๊ฒฝ ์ฌํญ์ ๋ฐ๋ก ๊ฐ์งํ๊ณ , ์ํ์ ๋ฐ๋ผ ๋์ ์ธ UI๋ฅผ ์ ๊ณตํ ์ ์๋ค.
const { register, watch } = useForm();
const nameValue = watch("name"); // 'name' ํ๋์ ์ค์๊ฐ ๊ฐ ์ถ์
8. setValue / getValues
- setValue : ์ ๋ ฅ ํ๋์ ๊ฐ์ ๋ณ๊ฒฝํ ๋ ์ฌ์ฉํ๋ค.
-getValues : ํ์ฌ ํผ์ ์๋ ์ ๋ ฅ ํ๋์ ๊ฐ์ ๊ฐ์ ธ์ค๋ ํจ์์ด๋ค.
const { setValue, getValues } = useForm();
setValue("name", "John Doe"); // 'name' ํ๋์ ๊ฐ์ 'John Doe'๋ก ์ค์
console.log(getValues("name")); // 'name' ํ๋์ ํ์ฌ ๊ฐ์ ์ถ๋ ฅ
9. useFormContext
useFormContext๋ react-hook-form ์ ์ปจํ ์คํธ API๋ฅผ ์ฌ์ฉํ์ฌ ์ค์ฒฉ๋ ์ปดํฌ๋ํธ์์ ํผ ์ํ๋ฅผ ์ฝ๊ฒ ๊ณต์ ํ ์ ์๋๋กํ๋ค. ์ฌ๋ฌ ์ปดํฌ๋ํธ์์ ํผ ๋ฐ์ดํฐ๋ฅผ ๊ด๋ฆฌํ ๋ ์ ์ฉํ๋ค.
import { useFormContext } from "react-hook-form";
function NestedComponent() {
const { register } = useFormContext();
return <input {...register("nestedField")} />;
}
10. Controller
Controller ๋ ์ ์ด ์ปดํฌ๋ํธ๋ฅผ ์ฌ์ฉํ ๋ react-hook-form๊ณผ ํตํฉํ ์ ์๋ ๋ฐฉ๋ฒ์ ์ ๊ณตํ๋ค.
์ ์ด ์ปดํฌ๋ํธ๋ ์์ฒด์ ์ผ๋ก ์ํ๋ฅผ ๊ด๋ฆฌํ๋ ์ปดํฌ๋ํธ๋ก ์ผ๋ฐ์ ์ผ๋ก๋ register ๋ก ์ฐ๊ฒฐ๋์ง ์๊ธฐ ๋๋ฌธ์
Controller ๋ฅผ ํตํด ํผ ์ํ์ ์ฐ๊ฒฐํ ์ ์๋ค.
react-select / Meterial-UI / Ant Design ๋ฑ ์ธ๋ถ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ปดํฌ๋ํธ๋ ์์ฒด ์ํ ๊ด๋ฆฌ ๋ก์ง์ ๊ฐ์ง๊ธฐ ๋๋ฌธ์
์ด๋ฅผ react-hook-form ๊ณผ ์ฐ๊ฒฐํ๋ ค๋ฉด Controller ๊ฐ ํ์ํ๋ค.
import { Controller, useForm } from "react-hook-form";
import Select from "react-select"; // ์ ์ด ์ปดํฌ๋ํธ
function MyForm() {
const { control, handleSubmit } = useForm();
return (
<form onSubmit={handleSubmit(onSubmit)}>
<Controller
name="select"
control={control}
render={({ field }) => <Select {...field} options={[{ value: '1', label: 'One' }]} />}
/>
<button type="submit">Submit</button>
</form>
);
}
react-select์ Controller ์ฌ์ฉ ์์
import React from 'react';
import { useForm, Controller, SubmitHandler } from 'react-hook-form';
import Select from 'react-select'; // ์ ์ด ์ปดํฌ๋ํธ์ธ react-select
// ํผ ๋ฐ์ดํฐ ํ์
์ ์
interface IFormInput {
favoriteColor: { value: string; label: string };
}
const options = [
{ value: 'red', label: 'Red' },
{ value: 'green', label: 'Green' },
{ value: 'blue', label: 'Blue' }
];
function MyForm() {
const { handleSubmit, control } = useForm<IFormInput>();
const onSubmit: SubmitHandler<IFormInput> = (data) => {
console.log(data); // ์ ํํ ๊ฐ ์ถ๋ ฅ
};
return (
<form onSubmit={handleSubmit(onSubmit)}>
<label htmlFor="color">Favorite Color:</label>
{/* Controller๋ก react-select๋ฅผ ์ฌ์ฉํ์ฌ ํผ๊ณผ ์ฐ๊ฒฐ */}
<Controller
name="favoriteColor"
control={control}
render={({ field }) => (
<Select
{...field}
options={options}
placeholder="Select a color"
/>
)}
/>
<button type="submit">Submit</button>
</form>
);
}
export default MyForm;
-> control : useForm์์ ๊ฐ์ ธ์ค๋ control์ ํผ ์ํ๋ฅผ ๊ด๋ฆฌํ๋ ๊ฐ์ฒด์ด๋ค. ์ด๋ฅผ Controller์ ํจ๊ป ์ฌ์ฉํ์ฌ
ํผ ์ํ์ ์ ์ด ์ปดํฌ๋ํธ๋ฅผ ์ฐ๊ฒฐํ ์ ์๋ค.
-> Controller : name ์์ฑ์ ํตํด ํผ์ ์ ๋ ฅ ํ๋ ์ด๋ฆ์ ์ค์ ํ๊ณ , control์ ํตํด ์ํ๋ฅผ ๊ด๋ฆฌํ๋ค.
rednter ํจ์๋ ์ ์ด ์ปดํฌ๋ํธ๋ฅผ ๋ ๋๋ง ํ๋ ์ญํ ์ ํ๋ฉฐ field ๋ผ๋ ๊ฐ์ฒด๋ฅผ ๋ฐ์ ํด๋น ์ปดํฌ๋ํธ์ ์ ๋ฌํ๋ค.
field ๋ ํผ ์ํ์ ์ด๋ฒคํธ( onChange, onBlur, value)๋ฅผ ๊ด๋ฆฌํ๋ ์์ฑ๋ค์ ํฌํจํ๋ค.
๊ธฐ๋ณธ ๊ฐ ์ค์ : Controller ๋ defaultValue๋ฅผ ํตํด ์ด๊ธฐ ๊ฐ์ ์ค์ ํ ์ ์์
๊ฒ์ฆ : rules ์ต์ ์ ์ฌ์ฉํ์ฌ ๊ฒ์ฆ ๊ท์น ์ถ๊ฐ ๊ฐ๋ฅ
<Controller
name="favoriteColor"
control={control}
defaultValue={options[0]} // ๊ธฐ๋ณธ ๊ฐ์ 'Red'๋ก ์ค์
rules={{ required: 'Please select a color' }} // ํ์ ์
๋ ฅ ๊ฒ์ฆ
render={({ field, fieldState }) => (
<>
<Select
{...field}
options={options}
placeholder="Select a color"
/>
{fieldState.error && <p>{fieldState.error.message}</p>}
</>
)}
/>
https://beomy.github.io/tech/react/react-hook-form/
[React] react-hook-form์ผ๋ก ํผ ๊ด๋ฆฌํ๊ธฐ
React Hook Form์ ์ฌ์ฉ์ ์ ๋ ฅ์ ๋ฐ๊ณ ๊ฒ์ฆํ๋ ๊ฒ์ ๋์ ์ฃผ๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ก, React์์ ํผ์ ๊ด๋ฆฌํ๋ ๊ฐ์ฅ ์ ๋ช ํ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ค ํ๋์ ๋๋ค. React Hook Form์ ์ฌ์ฉํ๋ฉด ์ฌ์ฉ์์๊ฒ ์ ๋ ฅ์ ๋ฐ๊ณ ๊ฒ
beomy.github.io
/@yesoryeseul/react-hook-form-%EC%95%8C%EA%B3%A0-%EC%93%B0%EC%9E%90
react-hook-form ์๊ณ ์ฐ์
โก๏ธ ๋จผ์ react-hook-form์ด๋ ๋ฌด์์ธ๊ฐ? > Performant, flexible and extensible forms with easy-to-use validation. ์ ํจ์ฑ ๊ฒ์ฌ๋ฅผ ์ฝ๊ฒ ํ ์ ์๋, ์ฑ๋ฅ์ด ์ฐ์ํ๊ณ ์ ์ฐํ๋ฉฐ ํ์ฅ ๊ฐ๋ฅํ form์ ์
velog.io
'STUDY' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
| ํด๋ก์ (Closure)๋? (1) | 2025.01.17 |
|---|---|
| [๋ผ์ด๋ธ๋ฌ๋ฆฌ] react-spring ์ ๋๋ฉ์ด์ ๊ตฌํ (1) | 2024.09.29 |
| <E2E ํ ์คํธ> playwright E2E ํ ์คํธ ๋ฐ ๊นํ๋ธ CI ์ค์ ํ๊ธฐ (1) | 2024.09.14 |
| [react-signature-canvas] ์ ์์๋ช ๊ตฌํํ๊ธฐ (1) | 2024.09.13 |
| axios ์ธ์คํด์ค (0) | 2024.09.10 |