본문 바로가기

ControllerWrapper로 React Hook Form 최적화하기

@Jeeqong 2025. 3. 8. 21:11
반응형
React Hook Form의 Controller를 감싸서 반복되는 설정을 줄이고 재사용성을 높이는 ControllerWrapper 컴포넌트를 소개합니다. 이 컴포넌트를 사용하면 다양한 입력 필드를 통합적으로 관리하고 유효성 검사도 쉽게 적용할 수 있습니다.

1.1. ControllerWrapper란?

ControllerWrapper는 react-hook-form의 Controller를 감싸서 보다 편리하게 사용할 수 있도록 만들어진 재사용 가능한 Form 컨트롤러 컴포넌트입니다.

 

🔹 주요 기능

  • Controller의 공통 설정을 한 곳에 모아 관리
  • 다양한 입력 필드(input, select, textarea, DatePicker 등) 지원
  • rules를 활용한 유효성 검사 적용 가능
  • React.forwardRef를 통해 외부에서 ref 사용 가능 

1.2. ControllerWrapper 코드 구현

아래는 ControllerWrapper의 코드입니다.

// components/ControllerWrapper.tsx
import React from 'react'
import {
	Control,
	Controller,
	FieldError,
	FieldValues,
	Path,
	RegisterOptions,
} from 'react-hook-form'

interface ControllerWrapperProps<T extends FieldValues> {
	name: Path<T> // name 타입 지정
	control: Control<T> // react-hook-form의 control 객체
	rules?: Omit<RegisterOptions<T, Path<T>>, 'setValueAs' | 'disabled' | 'valueAsNumber' | 'valueAsDate'>
	defaultValue?: any
	render: (props: RenderProps) => React.ReactElement
	type?: string
	[key: string]: any // 추가적인 나머지 props를 허용
}

export interface RenderProps {
	value: any
	onChange: (value: any) => void
	ref: React.Ref<any>
	error?: FieldError // 유효성 검사 오류 메시지
}

const ControllerWrapper = <T extends FieldValues>(
	{
		name,
		control,
		defaultValue,
		render,
		rules,
		...rest
	}: ControllerWrapperProps<T>,
	ref: React.Ref<any>,
) => {
	return (
		<Controllername={name}
			control={control}
			defaultValue={defaultValue}
			rules={rules}
			render={({ field, fieldState: { error } }) => {
				return render({
					...field,
					ref: field.ref,
					error,
					...rest,
				})
			}}
		/>
	)
}

export default ControllerWrapper


1.3. 사용 방법

1.3.1. useForm을 사용하여 control 가져오기

react-hook-form의 useForm()을 사용하여 control 객체를 가져옵니다.

import { useForm } from 'react-hook-form'
import ControllerWrapper from '@/components/ControllerWrapper'

type FormValues = {
  username: string
  age: number
}

export default function MyForm() {
  const { control, handleSubmit } = useForm<FormValues>()

  const onSubmit = (data: FormValues) => {
    console.log('폼 데이터:', data)
  }

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      {/* 텍스트 입력 필드 */}
      <ControllerWrappername="username"
        control={control}
        defaultValue=""
        rules={{ required: '이름을 입력해주세요' }}
        render={({ value, onChange, error }) => (
          <div>
            <inputtype="text"
              value={value}
              onChange={onChange}
              placeholder="이름을 입력하세요"
              className="border p-2"
            />
            {error && <p className="text-red-500">{error.message}</p>}
          </div>
        )}
      />

      {/* 숫자 입력 필드 */}
      <ControllerWrappername="age"
        control={control}
        defaultValue={0}
        rules={{ required: '나이를 입력해주세요', min: { value: 1, message: '나이는 1 이상이어야 합니다' } }}
        render={({ value, onChange, error }) => (
          <div>
            <inputtype="number"
              value={value}
              onChange={(e) => onChange(Number(e.target.value))}
              placeholder="나이를 입력하세요"
              className="border p-2"
            />
            {error && <p className="text-red-500">{error.message}</p>}
          </div>
        )}
      />

      <button type="submit" className="bg-blue-500 text-white p-2 mt-4">
        제출하기
      </button>
    </form>
  )
}


1.4. 주요 동작 원리

1️⃣ useForm()을 사용하여 control 객체를 가져옵니다.

2️⃣ ControllerWrapper를 사용하여 name, control, defaultValue, rules를 설정합니다.

3️⃣ render 함수를 통해 커스텀 입력 필드를 구성합니다.

4️⃣ onChange를 활용하여 입력 값이 변경될 때 React Hook Form에 자동으로 반영됩니다.

5️⃣ 제출 버튼 클릭 시 handleSubmit을 통해 onSubmit 함수가 실행됩니다.


1.5. 왜 ControllerWrapper를 사용할까?

✅ 1.5.1. 반복되는 Controller 사용을 간소화

매번 Controller를 직접 사용하면 코드가 길어지지만, ControllerWrapper를 활용하면 재사용 가능하고 유지보수가 쉬워집니다.

✅ 1.5.2. 유효성 검사 적용이 쉬움

rules 속성을 사용하여 필드마다 개별적인 유효성 검사를 손쉽게 추가할 수 있습니다.

✅ 1.5.3. 다양한 입력 컴포넌트에 적용 가능

render를 활용하면 input, select, textarea, DatePicker 등 어떤 입력 필드에도 적용할 수 있습니다.


1.6. 결론 🚀

✅ ControllerWrapper는 react-hook-form의 Controller를 감싸서 입력 필드의 상태 관리, 검증 및 UI 렌더링을 쉽게 할 수 있도록 도와주는 컴포넌트입니다.

✅ render 함수를 사용하여 커스텀 UI를 적용할 수 있어 다양한 입력 필드를 통합적으로 관리할 수 있습니다.

✅ rules를 통해 유효성 검사도 간편하게 추가할 수 있어 유지보수하기 쉬운 코드 구조를 만듭니다.


💡 이제 ControllerWrapper를 활용하여 보다 효율적인 Form 컴포넌트를 만들어 보세요! 🚀

 

반응형
Jeeqong
@Jeeqong :: JQVAULT

Jeeqong's vault : 정보/기록을 쌓아두는 공간 웹개발 포스팅 일상 리뷰를 기록하는 공간입니다.

공감하셨다면 ❤️ 구독도 환영합니다! 🤗

목차