// ๊ธฐ์กด ์ฝ๋
const [addFeedData, setAddFeedData] = useState(INITIAL_ADD_FEED_DATA);
const handleInputChange = (e, field) => {
const { value } = e.target;
setAddFeedData(state => ({
...state,
[field]: value,
}));
};
๋งค ์
๋ ฅ๋ง๋ค ๋ฆฌ๋ ๋๋ง์ด ๋ฐ์ํ๊ณ , ๋ฐ์ดํฐ๋ฅผ ๊ฐ๋ณ์ ์ผ๋ก ๋ฐ์์ค๋ ๋นํจ์จ์ ์ธ ๊ตฌ์กฐ์์ต๋๋ค.
์ผ๋ฐ์ ์ผ๋ก ์ฌ์ฉ์์ ์
๋ ฅ์ ๊ธฐ๋ฐ์ผ๋ก ์์ ์ state๋ฅผ ๊ด๋ฆฌํ๊ณ ์
๋ฐ์ดํธํฉ๋๋ค. React์์๋ ๋ณ๊ฒฝํ ์ ์๋ state๊ฐ ์ผ๋ฐ์ ์ผ๋ก ์ปดํฌ๋ํธ์ state ์์ฑ์ ์ ์ง๋๋ฉฐ setState()์ ์ํด ์
๋ฐ์ดํธ๋ฉ๋๋ค.
ํผ์ ๋ ๋๋งํ๋ React ์ปดํฌ๋ํธ๋ ํผ์ ๋ฐ์ํ๋ ์ฌ์ฉ์ ์
๋ ฅ๊ฐ์ ์ ์ดํฉ๋๋ค. ์ด๋ฌํ ๋ฐฉ์์ผ๋ก React์ ์ํด ๊ฐ์ด ์ ์ด๋๋ ์
๋ ฅ ํผ ์๋ฆฌ๋จผํธ๋ฅผ โ์ ์ด ์ปดํฌ๋ํธ (controlled component)โ๋ผ๊ณ ํฉ๋๋ค.
useState๋ฅผ ์ฌ์ฉํ ๋ onChange์์ ๋ฐ์์ค๋ ๊ฐ์ ๋นํจ์จ์ ์ด๋ผ๊ณ ์๊ฐํฉ๋๋ค. ํ๋ํ๋ ๊ฐ์ ๋ฐ์์ค๊ธฐ ๋๋ฌธ์ ์๋ ์ญ์ ๋๋ฆด ์ ๋ฐ์ ์๋ ๋จ์ ์ด ์กด์ฌํ ๊ฒ์ด๊ธฐ์..
์ค์ ๋ก useState์์ input๊ฐ์ onChange๋ก ๋ฐ์์ค๊ฒ ๋๋ค๋ฉด...
ex) ๊ฐ๋๋ค -> ใฑ, ๊ฐ, ๊ฐใด, ๊ฐ๋, ๊ฐ๋ใท, ๊ฐ๋๋ค
์ ๊ฐ์ ์ํฉ์์๋ ๊ณ์์ ์ผ๋ก ๋ฐ์ดํฐ๋ฅผ ํ๋ํ๋ ๋ฐ์์ค๋ฏ๋ก ๋นํจ์จ์ ์ผ ๊ฒ์ ๋๋ค.
๋น์ ์ด ์ปดํฌ๋ํธ๋ก ๋ค๋งํ๊ฒ์ useRef()๋ผ๊ณ ์๊ฐํ๋๋ฐ์. ref๋ ๊ฐ์ ์
๋ฐ์ดํธ ํ์ฌ๋ ๋ฆฌ๋ ๋๋ง ๋์ง์๋ ํน์ฑ์ผ๋ก, ์
๋ ฅ์ด ๋ชจ๋ ๋๊ณ ๋ ํ ref๋ฅผ ํตํด ๊ฐ์ ํ๋ฒ์ ๊ฐ์ ธ์์ ํ์ฉํฉ๋๋ค. state๋ก ๊ฐ์ ๊ด๋ฆฌํ์ง ์๊ธฐ ๋๋ฌธ์ ๊ฐ์ด ๋ฐ๋๋๋ง๋ค ๋ฆฌ๋ ๋๋ง์ ํ์ง ์๊ณ ๊ฐ์ ํ๋ฒ์ ๊ฐ์ ธ์ฌ ์ ์๋ ์ฑ๋ฅ์์ ์ด์ ์ด ์์ผ๋, ๋ฐ์ดํฐ๋ฅผ ์๋ฒฝํ๊ฒ ๊ฐ์ ธ์ฌ ์ ์๋ ๋จ์ ์ด ์๊ฒ ์ฃ ..
๊ทธ๋ผ ์ด๋ฌํ ๋ฐฉ๋ฒ์ธ์ ๋ค๋ฅธ ๋ฐฉ๋ฒ์ ์ฌ์ฉํด ๋ณผ ์๋ ์์๊น?
๋ง์นจ ๊ทธ๊ฒ๊ณผ ๊ฒธํด์ ํด๋น ํ๋ก์ ํธ์์ ์ ํจ์ฑ ๊ฒ์ฌ๊ฐ ํ์ํ๊ธฐ ๋๋ฌธ์ ๊ด๋ จ ์ ๋ณด๋ฅผ ์์นํด๋ณด์๋ค. ํน์ ๋ฆฌ์กํธ์์ ๊ถ์ฅํ๊ณ ๋ง์ด ์ฌ์ฉํ๋ ์ ํจ์ฑ ๊ฒ์ฌ๋ ์์๊น?
React Hook์ ์ฌ์ฉํ์ฌ ํผ ๊ด๋ฆฌ์ ์ ํจ์ฑ ๊ฒ์ฌ๋ฅผ ๊ฐ๋จํ๊ฒ ์ค์ํ ์ ์๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ๋ฐ๊ฒฌํ๊ฒ ๋์์ต๋๋ค
react-hook-form์ ๋น์ ์ด ์ปดํฌ๋ํธ๋ก ๋ ๋๋ง์ ์ต์ ํ ํ ์ ์๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ผ๊ณ ํ๋ค์?
import { useForm } from "react-hook-form";
const {
handleSubmit, // form onSubmit์ ๋ค์ด๊ฐ๋ ํจ์
register, // onChange ๋ฑ์ ์ด๋ฒคํธ ๊ฐ์ฒด ์์ฑ
watch, // register๋ฅผ ํตํด ๋ฐ์ ๋ชจ๋ ๊ฐ ํ์ธ
formState: { errors }, // errors: register์ ์๋ฌ ๋ฉ์ธ์ง ์๋ ์ถ๋ ฅ
} = useForm();
import { useForm } from "react-hook-form";
function YourForm() {
const { register, handleSubmit, formState: { errors } } = useForm();
const onSubmit = (data) => {
console.log(data); // ํผ ๋ฐ์ดํฐ๊ฐ ์ฌ๊ธฐ๋ก ๋ค์ด์ต๋๋ค
};
return (
<form onSubmit={handleSubmit(onSubmit)}>
<input {...register("์ด๋ฆ")} />
<button type="submit">์ ์ถ</button>
</form>
);
}
register๋?// ๊ธฐ๋ณธ ์ฌ์ฉ
<input {...register("username")} />
// ์ ํจ์ฑ ๊ฒ์ฌ ๊ท์น ์ถ๊ฐ
<input {...register("username", {
required: true, // ํ์ ์
๋ ฅ
minLength: 2, // ์ต์ 2๊ธ์
maxLength: 20 // ์ต๋ 20๊ธ์
})} />
<input {...register("username", { required: true })} />
{errors.username && <p>์ด๋ฆ์ ์
๋ ฅํด์ฃผ์ธ์!</p>}
const { register } = useForm({
defaultValues: {
username: "๊น์ฝ๋ฉ",
email: "kim@coding.com"
}
});
์ค์ ์ฌ์ฉ ์์:
function SignupForm() {
const { register, handleSubmit, formState: { errors } } = useForm();
const onSubmit = (data) => {
console.log(data);
};
return (
<form onSubmit={handleSubmit(onSubmit)}>
<div>
<label>์ด๋ฉ์ผ</label>
<input
{...register("email", {
required: "์ด๋ฉ์ผ์ ํ์์
๋๋ค",
pattern: {
value: /\S+@\S+\.\S+/,
message: "์ด๋ฉ์ผ ํ์์ด ์๋๋๋ค"
}
})}
/>
{errors.email && <p>{errors.email.message}</p>}
</div>
<div>
<label>๋น๋ฐ๋ฒํธ</label>
<input
type="password"
{...register("password", {
required: "๋น๋ฐ๋ฒํธ๋ ํ์์
๋๋ค",
minLength: {
value: 8,
message: "8์๋ฆฌ ์ด์ ์
๋ ฅํด์ฃผ์ธ์"
}
})}
/>
{errors.password && <p>{errors.password.message}</p>}
</div>
<button type="submit">๊ฐ์
ํ๊ธฐ</button>
</form>
);
}
์ฅ์ :
1. ๊ฐ๋จํ ํผ ๊ด๋ฆฌ
2. ์ ์ ์ฝ๋๋ก ์ ํจ์ฑ ๊ฒ์ฌ ๊ตฌํ
3. ์๋ฌ ์ฒ๋ฆฌ๊ฐ ์ฌ์
4. ๋ฆฌ๋ ๋๋ง ์ต์ ํ
๊ธฐ์กด ๋ฐฉ์๊ณผ์ ์ฐจ์ด:
// ๊ธฐ์กด ๋ฐฉ์
const [email, setEmail] = useState("");
<input
value={email}
onChange={(e) => setEmail(e.target.value)}
/>
// React Hook Form
<input {...register("email")} />
React Hook Form์ ์ฌ์ฉํ๋ฉด useState๋ก ๊ฐ๊ฐ์ input ์ํ๋ฅผ ๊ด๋ฆฌํ ํ์๊ฐ ์์ด์ ธ์ ์ฝ๋๊ฐ ํจ์ฌ ๊ฐ๋จํด์ง๋๋ค!
yarn add react-hook-form
์ ์ฌ์ฉํ๋ ์ด๋ผ...
yarn add react-hook-form
yarn add v1.22.22
[1/4] ๐ Resolving packages...
[2/4] ๐ Fetching packages...
error react-router-dom@7.1.5: The engine "node" is incompatible with this module. Expected version ">=20.0.0". Got "18.20.5"
error Found incompatible module.
info Visit https://yarnpkg.com/en/docs/cli/add for documentation about this command.
์?? ๋ญ๊ฐ ์๋ชป๋๊ฑฐ์ง..
์ด๋ด๋ ๋ญ๋ค? ์์น๋ค..
์์ธ์ ์ฐพ์๋ณด๋, react-router-dom๊ณผ์ ๋ฒ์ ์ด ๋ง์ง ์๋ ๋ฌธ์ ๊ฐ ๋ฐ์ํ๊ฒ..
ํ์ฌ ์ฌ์ฉ์ค์ธ router๊ธฐ๋ฅ์ ์ต๋ํ ๋ฌด๋ฆฌ๊ฐ ๊ฐ์ง ์๋๋ก ๋ฒ์ ์ ์กฐ์ ํ์๋ค.
as-is: "react-router-dom": "^7.1.5"
to-be: "react-router-dom": "6.4.0", "react-hook-form": "^7.54.2",
์๊ณผ ๊ฐ์ด ๋ง์ถ์ด ์ฃผ๋, ์ ์์ ์ผ๋ก ์๋!!
// โ ์ฒ์ ์๋ํ ๋ฐฉ์
<form onSubmit={(e) => {
e.preventDefault()
handleSubmit(handleAddFeed)
}}>
// โ
์ฌ๋ฐ๋ฅธ ๋ฐฉ์
<form onSubmit={handleSubmit(handleAddFeed)}>
handleSubmit์ด ์ด๋ฏธ preventDefault๋ฅผ ์ฒ๋ฆฌํ๋ค๋ ๊ฑธ ๋ชฐ๋ผ์ ๋ฐ์ํ ์ค์์์ต๋๋ค.
// โ ๋ฌธ์ ์ ์ฝ๋
<StFormTitleInput
value={addFeedData.title}
onChange={(e) => handleInputChange(e, 'title')}
/>
// โ
ํด๊ฒฐ: register ํจ์ ์ฌ์ฉ
<StFormTitleInput
{...register("title", { required: true })}
/>
React Hook Form๊ณผ input์ด ์ ๋๋ก ์ฐ๋๋์ง ์์ ๋ฐ์ํ ๋ฌธ์ ์์ต๋๋ค.
์ค์ง์ ์ผ๋ก ์ด๋ค ์ฝ๋๋ฅผ ์ฌ์ฉํ ๊ฑฐ์ผ! ๋ผ๊ณ ๋ช
์ํ์ง ์์์
{...register("title", {
required: true,
minLength: {
value: 6,
message: "์ ๋ชฉ์ ์ต์ 6์ ์ด์์ด์ด์ผ ํฉ๋๋ค"
},
maxLength: {
value: 50,
message: "์ ๋ชฉ์ ์ต๋ 50์๋ฅผ ์ด๊ณผํ ์ ์์ต๋๋ค"
},
setValueAs: (value) => value.trim()
})}
setValueAs๋ก ๋ฐ๋ก ๊ณต๋ฐฑ์ ๊ฑฐ๋ฅผ ์งํํด์ฃผ๊ณ ..
{errors?.title && (
<p>
{errors.title.type === "required" && "์ ๋ชฉ์ ํ์์
๋๋ค."}
{errors.title.type === "minLength" && "์ ๋ชฉ์ ์ต์ 6์ ์ด์์ด์ด์ผ ํฉ๋๋ค"}
{errors.title.type === "maxLength" && "์ ๋ชฉ์ ์ต๋ 50์๋ฅผ ์ด๊ณผํ ์ ์์ต๋๋ค"}
</p>
)}
์๋ ํผ ์ ์ถ ๋ฐฉ์ง
๋ถํ์ํ ์ฝ๋ ์ ๊ฑฐ
// ์ด๋ฐ ์ฝ๋๋ค์ด ๋ชจ๋ ํ์ ์์ด์ง
const [addFeedData, setAddFeedData] = useState(INITIAL_ADD_FEED_DATA);
const handleInputChange = (e, field) => {...};
useEffect(() => ...์๋ต ,[])
๊น๋ํ ์๋ฌ ์ฒ๋ฆฌ
formState: { errors }๋ก ์ฝ๊ฒ ์๋ฌ ์ํ ํ์
React Hook Form์ ๋์
ํ๋ฉด์ ๊ฒช์ ์ํ์ฐฉ์ค๋ค์ด ์คํ๋ ค ์ข์ ํ์ต ๊ฒฝํ์ด ๋์์ต๋๋ค. ๊ณต์๋ฌธ์๋ฅผ ์ฝ๊ณ ์ ํ๋๊ฑด ์์ผ ์ด๋ ต์ต๋๋ค.
react-hook-form ๊ณต์๋ฌธ์