본문 바로가기

교육

"TypeScript 제네릭 기반 Form 재사용 패턴: React Hook Form과 함께하는 고급 Form 설계"

반응형

 

 

1. 필요 라이브러리 설치 방법

React18 + TypeScript + react-hook-form 기반 환경

 

프로젝트 생성 (Vite 기준)

npm create vite@latest my-form-app --template react-ts
cd my-form-app

 

또는 Yarn

yarn create vite my-form-app --template react-ts
cd my-form-app

 

 

react-hook-form 설치

npm install react-hook-form

또는

yarn add react-hook-form

 

2. 코드 리뷰

import { SubmitHandler } from 'react-hook-form';

/**
 * @template T
 * Search members of react-hook-form
 */
export type TSearchBaseProps<T> = {
  defaultValues?: T;
  onSubmit: SubmitHandler<T>;
  onReset?: () => void;
};

 

코드 분석 결과

✔ 제네릭 기반 Form Props 인터페이스

TSearchBaseProps<T>는 Form 컴포넌트의 공통 기반 Props를 만들기 위한 TypeScript 제네릭 타입이다.

✔ SubmitHandler<T>

react-hook-form에서 제공하는 타입
→ submit 이벤트에서 입력 데이터 타입을 정확히 보장한다.

✔ defaultValues

Form의 초기 값 설정
선택적(optional)이라서 필요 없을 경우 생략 가능

✔ onSubmit

Form 제출 시 호출되는 필수 함수

✔ onReset

Reset 버튼 또는 리셋 액션 시 실행되는 선택적 함수

🔧 장점

항목설명
타입 안정성 모든 Form 데이터 타입이 명확히 추론됨
재사용성 증가 다양한 필터 Form 컴포넌트를 표준형으로 설계 가능
유지보수 쉬움 시스템 규모가 커질수록 큰 효과
react-hook-form 구조와 완벽 호환 TS 기반 RHF 최적화

 

 

목표

  • 제네릭 기반 Form Props 설계 이해
  • react-hook-form + TS에서의 타입 안전성 구현 방법
  • Form 화면을 재사용 가능하게 만드는 방법 학습

 

왜 제네릭 Form 구조가 필요한가

문제점(기존 방식)

❌ Form마다 Props와 구조가 매번 다름
❌ submit 시 타입이 any로 처리됨
❌ UI 재사용 불가능

해결 방법

✔ TypeScript 제네릭을 이용한 Form 표준화
✔ 모든 Form은 동일한 공통 Props를 가지도록 설계
✔ 데이터 타입 안전성 확보

 

 

핵심 코드

export type TSearchBaseProps<T> = {
  defaultValues?: T;
  onSubmit: SubmitHandler<T>;
  onReset?: () => void;
};

 

  • <T>: Form 데이터 타입
  • defaultValues?: T: 초기값
  • SubmitHandler<T>: react-hook-form에서 제공하는 타입
  • 재사용 가능한 구조를 통해 필터폼, 등록폼 등에 모두 대응 가능

 

 

예제 코드 설명

  • Employee Filter Form 예제
  • Generic 기반 Form Component
  • Data 타입 정의
  • submit/reset 이벤트 처리

 

1) 데이터 타입 정의

// types/TEmployeeFilter.ts
export type TEmployeeFilter = {
  name: string;
  department: string;
  joinDate?: string;
};

 

2) 공통 Form Props 타입

// types/TFilterBaseProps.ts
import { SubmitHandler } from "react-hook-form";

export type TFilterBaseProps<T> = {
  defaultValues?: T;
  onSubmit: SubmitHandler<T>;
  onReset?: () => void;
};

 

3) 제네릭 Form Component

// components/GenericFilterForm.tsx
import { useForm } from "react-hook-form";
import { TFilterBaseProps } from "../types/TFilterBaseProps";

export function GenericFilterForm<T>(props: TFilterBaseProps<T>) {
  const { defaultValues, onSubmit, onReset } = props;

  const { register, handleSubmit, reset } = useForm<T>({ defaultValues });

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <input {...register("name" as any)} placeholder="이름" />
      <input {...register("department" as any)} placeholder="부서" />
      <input {...register("joinDate" as any)} type="date" />

      <button type="submit">검색</button>
      <button
        type="button"
        onClick={() => {
          reset();
          onReset?.();
        }}
      >
        초기화
      </button>
    </form>
  );
}

 

4) 실제 페이지에서 사용

// pages/EmployeeSearchPage.tsx
import React from "react";
import { GenericFilterForm } from "../components/GenericFilterForm";
import { TEmployeeFilter } from "../types/TEmployeeFilter";

export default function EmployeeSearchPage() {
  const defaultValues: TEmployeeFilter = {
    name: "",
    department: "",
    joinDate: "",
  };

  const handleSubmit = (data: TEmployeeFilter) => {
    console.log("검색 결과:", data);
  };

  const handleReset = () => {
    console.log("검색창 초기화 완료");
  };

  return (
    <div>
      <h2>직원 검색</h2>

      <GenericFilterForm<TEmployeeFilter>
        defaultValues={defaultValues}
        onSubmit={handleSubmit}
        onReset={handleReset}
      />
    </div>
  );
}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

A modern, clean, and professional cover image for a programming lecture titled "TypeScript Generic-Based Form Reusability Pattern: Advanced Form Design with React Hook Form". Include visual elements representing TypeScript (e.g., the TS logo or type annotations), React Hook Form (e.g., form components, hooks), and reusable form patterns (e.g., modular, interconnected form blocks or components). Use a tech-oriented color scheme, such as blues, purples, or dark themes with bright accents, to convey a high-level, advanced programming concept. Include abstract representations of generic types and dynamic forms. The style should be sleek, contemporary, and suitable for a developer audience.

 

react-helmet을 완전히 제거하고 react-helmet-async로 대체 (가장 추천)

npm uninstall react-helmet
npm install react-helmet-async

 

import { HelmetProvider, Helmet } from "react-helmet-async";

function App() {
  return (
    <HelmetProvider>
      <Helmet>
        <title>My App</title>
      </Helmet>
      <div>...</div>
    </HelmetProvider>
  );
}

 

반응형