React Hook Form으로 커스텀 폼 아이템 만들기
2024-09-25 17:39:43소개
React는 현재 가장 인기 있는 프론트엔드 라이브러리 중 하나로, 컴포넌트 기반의 접근 방식을 통해 개발자들이 UI를 효율적으로 구축할 수 있게 해줍니다. 그 중에서도 React Hook Form은 폼 관리를 손쉽게 할 수 있는 라이브러리로 많은 사랑을 받고 있습니다. 하지만 다양한 요구에 맞춰 우리가 필요로 하는 커스텀 폼 아이템을 만드는 것은 개발자에게 새로운 도전을 제시합니다. 이 글에서는 React Hook Form을 사용하여 커스텀 폼 아이템을 만드는 방법에 대해 알아보겠습니다.
배경 및 필요성
기본 HTML 폼 요소들은 충분히 편리하지만, 때로는 여러 요소들이 결합된 보다 복잡한 사용자 입력 컨트롤이 필요합니다. 예를 들어, 사용자에게 특정 옵션을 선택하게 하면서 선택된 옵션에 따라 추가적인 정보를 표시해야 하는 경우입니다. 여기서 커스텀 폼 아이템이 유용하게 사용됩니다. React Hook Form을 이용하면 상태 관리를 간소화할 수 있지만, 특정한 기능을 가진 커스텀 아이템을 통해 더 나은 사용자 경험을 제공할 수 있습니다.
특히 다양한 API로부터 얻은 데이터를 기반으로 동적으로 작동하는 폼 필드의 필요성이 커지고 있습니다. 이 글에서는 이를 해결하기 위해 DogSelect라는 형태의 커스텀 폼 아이템을 만들어 보겠습니다. 이 아이템은 사용자가 개 품종을 선택할 수 있으며, 선택된 품종에 따라 관련 이미지를 표시합니다.
핵심 내용
커스텀 폼 아이템이란?
커스텀 폼 아이템은 여러 개의 폼 아이템과 그 값의 조합으로, 필요할 때마다 유연하게 사용할 수 있는 재사용 가능한 UI 컴포넌트입니다. 커스텀 폼 아이템은 필수 값과 onChange 이벤트를 props로 받아 개발자가 원하는 대로 동작하도록 구현할 수 있습니다. 이를 통해 코드의 중복을 줄이고, 유지보수성을 높일 수 있습니다.
DogSelect 컴포넌트 작성하기
이제 DogSelect 컴포넌트를 만들어 보겠습니다. 이 컴포넌트는 사용자가 선택한 개의 품종에 따라 해당 품종의 이미지를 불러오는 기능을 합니다.
1. React Hook Form 설치하기
먼저, 프로젝트에 react-hook-form 라이브러리를 설치합니다.
npm i react-hook-form
2. DogSelect.tsx 파일 생성하기
프로젝트 내에 dog-select.tsx라는 파일을 생성하고, 아래의 코드를 추가합니다.
import { forwardRef, useEffect, useState } from "react";
export type TDogSelectValue = {
breed: string;
imgUrl: string;
};
type TDogSelectProps = {
value: TDogSelectValue;
onChange: Function;
};
interface IDogApiResponse {
message: Object | Array<string> | string;
}
export const DogSelect = forwardRef<HTMLDivElement, TDogSelectProps>(
({ value, onChange }: TDogSelectProps, ref) => {
const [breeds, setBreeds] = useState<string[]>([]);
useEffect(() => {
fetchAllBreeds().then((res) => setBreeds(res));
}, []);
const handleOnSelect = (e: React.ChangeEvent<HTMLSelectElement>) => {
const selectedBreed = e.target.value;
fetchRandomDogImgByBreed(selectedBreed).then((imgUrl) => {
const newValue: TDogSelectValue = {
breed: selectedBreed,
imgUrl,
};
onChange(newValue);
});
};
return (
<div className="dog-selector" ref={ref}>
<select onChange={handleOnSelect} value={value.breed}>
<option disabled value="pick a breed">
품종 선택
</option>
{breeds.map((b) => (
<option key={b} value={b}>
{b}
</option>
))}
</select>
{value.imgUrl && <img src={value.imgUrl} alt="dog picture" />}
</div>
);
}
);
const fetchAllBreeds = async () => {
const res = await fetch("https://dog.ceo/api/breeds/list/all");
const resJson: IDogApiResponse = await res.json();
return Object.keys(resJson.message);
};
const fetchRandomDogImgByBreed = async (breed: string) => {
const res = await fetch(`https://dog.ceo/api/breed/${breed}/images/random`);
const resJson: IDogApiResponse = await res.json();
return resJson.message as string;
};
이 코드는 DogSelect 컴포넌트를 정의합니다. useEffect를 사용하여 애플리케이션이 마운트될 때 모든 개 품종을 가져오고, 사용자가 품종을 선택할 때마다 해당 품종의 이미지를 가져옵니다. 이를 통해 이미지와 품종을 한 번의 선택으로 표시할 수 있습니다.
예시
App.tsx에서 DogSelect 사용하기
이제 App.tsx 파일에서 DogSelect를 사용해보겠습니다. 사용자가 개 품종을 선택하거나 제출 버튼을 클릭할 때 폼 검증이 이루어집니다.
import { useForm, Controller, SubmitHandler } from "react-hook-form";
import { DogSelect, TDogSelectValue } from "./components/dog-select";
type TFormValues = {
DogPicture: TDogSelectValue;
};
export default function App() {
const {
handleSubmit,
control,
formState: { errors },
} = useForm<TFormValues>({
defaultValues: {
DogPicture: {
breed: "pick a breed",
imgUrl: "",
},
},
mode: "onChange",
});
const onSubmit: SubmitHandler<TFormValues> = (data) => {
alert(
`제출 성공!! 품종: ${data.DogPicture.breed} 이미지 URL: ${data.DogPicture.imgUrl}`
);
};
return (
<form onSubmit={handleSubmit(onSubmit)}>
<Controller
name="DogPicture"
control={control}
rules={{
validate: (value: TDogSelectValue) => {
return value.breed === "corgi" || "잘못된 개 품종입니다.";
},
}}
render={({ field }) => <DogSelect {...field} />}
/>
{errors.DogPicture?.type === "validate" && (
<p role="alert" style={{ color: "red" }}>
잘못된 개 품종입니다.
</p>
)}
<input type="submit" />
</form>
);
}
위의 코드에서는 Controller 컴포넌트를 사용하여 DogSelect를 폼 상태에 연결합니다. 사용자가 품종을 선택한 후, 'corgi'가 아닌 품종이 선택되면 오류 메시지를 표시하며, 모든 조건을 충족하면 제출 처리로 이어집니다.
결론
이번 포스트에서는 React Hook Form을 이용하여 커스텀 폼 아이템인 DogSelect를 만드는 방법을 소개하였습니다. 이 예시를 통해 사용자 경험을 향상시키고, 조건에 따라 유연하게 동작하는 폼 필드를 구현할 수 있는 방법을 배웠습니다. 커스텀 폼 아이템은 다양한 상황에서 재사용 가능하며 코드의 일관성을 높이는 데 큰 기여를 할 것입니다. 앞으로 더욱 발전된 커스텀 폼 아이템을 통해 복잡한 사용자 입력을 손쉽게 처리할 수 있는 방법을 모색해보세요!