React Hook Form์ ์๋ก ๋น์ทํ ๊ธฐ๋ฅ๋ค์ ๋น๊ตํด ๋ณด์
์ด๋ฒ ํฌ์คํ ์์๋ React Hook Form์ ์ฌ์ฉํ๋ฉด์ ๋๊ผ๋ ๋น์ทํ ๊ธฐ๋ฅ์ ํ๋ API๋ค์ ๋น๊ตํ๊ณ ์ฌ์ฉํ๋ฉฐ ๋๋ ์ ๋ค์ ์ ๋ฆฌํด ๋ณด์์ต๋๋ค.
1๏ธโฃ Controller vs. useController
Controller
๋ useController
๋ฅผ ์ฌ์ฉํ์ฌ React Hook Form์ ๊ธฐ๋ฅ์ ์ฝ๊ฒ ์ ์ฉํ ์ ์์ต๋๋ค.Controller
function Component() {
const { control } = useForm<{type: string}>();
return (
<Controller
control={control}
name='type'
render={({field : {onChange, value}}) => (
<input
type='input'
value={value}
onChange={onChange}
/>
)}
/>
)
}
Controller
๋ฅผ ์ฌ์ฉํ๋ฉด์ ๋๊ผ๋ ์ ์, Controller
์ render
์์ฑ์ return
๋ฌธ์์ ์ฌ์ฉํ๋ ์ปดํฌ๋ํธ์ ์์ฑ์ด ๋ง์์ง์๋ก, ๋๋ ํ ์ปดํฌ๋ํธ์ ์ฌ์ฉ๋๋ Controller
๊ฐ ๋ง์์ง์๋ก ์ฝ๋ ๋ผ์ธ๊ณผ ๋ค์ฌ์ฐ๊ธฐ ํ์๊ฐ ์ฆ๊ฐํด ๊ฐ๋
์ฑ์ด ๋จ์ด์ง๋ค๋ ๊ฒ์
๋๋ค.
Controller
์ ๋์ผํ ๊ธฐ๋ฅ์ ํ๋ useController
ํ
์ ์ฌ์ฉํ ์ ์์ต๋๋ค.
useController
function Component() {
const { control } = useForm<{type: string}>()
const { field } = useController({ name: 'type', control })
return (
<input
type='input'
value={field.value}
onChange={field.onChange}
/>
)
}
2๏ธโฃ setValue vs. reset
React Hook Form - useForm: reset์ ๋ฐ๋ฅด๋ฉด reset
์ ๋๋์ ๋ฐ์ดํฐ ๋ณ๊ฒฝ์ ํ ๋ ์ฉ์ดํ๊ณ , setValue
๋ ์๋์ ๋ฐ์ดํฐ๋ฅผ ๋ณ๊ฒฝํ ๋ ์ฉ์ดํฉ๋๋ค.
์ ๋ ๋ชจ๋ ํผ์ ๋ณ๊ฒฝํ๋ ๊ฒฝ์ฐ๋ reset
์, ํน์ ํ๋๋ง ๋ณ๊ฒฝํ๋ ๋ฉ์๋๋ฅผ ์์ฑํ ๋๋ setValue
๋ฅผ ์ฌ์ฉํ์ต๋๋ค.
import { useForm } from 'react-hook-form';
export function Component() {
const { setValue, reset } =
useForm();
// ์๋ต
useEffect(() => {
if (data) {
const {
title,
groupId,
address,
latitude,
longitude,
contents,
maxHumanCount,
date,
status,
} = data;
reset({
title,
groupId,
address,
latitude,
longitude,
contents,
date,
maxHumanCount,
status,
});
}
}, [data, reset]);
const setGroup = (groupId: string) => {
setValue('groupId', groupId);
}
// ์๋ต...
}
3๏ธโฃ rules vs. schema
Controller
๋ useController
๋ฅผ ์ฌ์ฉํ ๋, rules
์์ฑ์ ์ง์ ํ์ฌ ํ๋์ ๊ท์น์ ์ง์ ํ ์ ์์ต๋๋ค.
rules
import { useController, useForm } from "react-hook-form";
export default function App() {
const { control } = useForm({ mode: "all" });
const {
field,
fieldState: { error },
} = useController({
name: "text",
control,
rules: { required: "Text is required" },
});
return (
<>
<input onChange={field.onChange} value={field.value} />
{error && <p>{error?.message}</p>}
</>
);
}
schema
schema๋ฅผ ์ง์ ์์ฑํด์ ์ฌ์ฉํ ๋๋ yup
, zod
, joi
์ ๊ฐ์ schema validation ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ํจ๊ป ์ฌ์ฉํ ์ ์์ต๋๋ค.
import { useController, useForm } from "react-hook-form";
import { yupResolver } from "@hookform/resolvers/yup";
import * as yup from "yup";
export default function App() {
const schema = yup.object().shape({
text: yup.string().required("Text is required"),
});
const { control } = useForm({ mode: "all", resolver: yupResolver(schema) });
const {
field,
fieldState: { error },
} = useController({
name: "text",
control,
});
return (
<>
<input onChange={field.onChange} value={field.value} />
{error && <p>{error?.message}</p>}
</>
);
}
๋ค์๊ณผ ๊ฐ์ด yup
์ test
๋ฉ์๋๋ก ์ปค์คํ
์๋ฌ ํ์
์ ์๋ฌ ๋ฉ์์ง๋ฅผ ๋ง๋ค์ด ์ฌ์ฉํ ์๋ ์์ต๋๋ค. ์ฃผ๋ก API ์์ฒญ์ ํตํด ๋๋ค์ ์ค๋ณต ํ์ธ๊ณผ ๊ฐ์ ์ ์ฐจ๋ฅผ ๊ฑฐ์น๊ณ ์ถ์ ๋ schema validation์ ์ฌ์ฉํ์ต๋๋ค.
import { useController, useForm } from "react-hook-form";
import { yupResolver } from "@hookform/resolvers/yup";
import * as yup from "yup";
export default function App() {
const duplicated = ["a", "b", "c", "aa", "aaa", "bb", "bbb", "cc", "ccc"];
const schema = yup.object().shape({
text: yup
.string()
.required("Text is required")
.test(
"Unique",
"Values need te be unique",
(values) => !duplicated.includes(values)
),
});
const { control } = useForm({ mode: "all", resolver: yupResolver(schema) });
const {
field,
fieldState: { error },
} = useController({
name: "text",
control,
});
return (
<>
<input onChange={field.onChange} value={field.value} />
{error && <p>{error?.message}</p>}
</>
);
}