Skip to content

Controller

제어된 입력을 위한 래퍼 컴포넌트

</> Controller: Component

React Hook Form은 비제어 컴포넌트와 네이티브 입력을 기본으로 사용하지만, React-Select, AntD, MUI와 같은 외부 제어 컴포넌트를 사용해야 할 때가 있습니다. 이 래퍼 컴포넌트는 이러한 컴포넌트를 더 쉽게 다룰 수 있게 도와줍니다.

Props


아래 표는 Controller의 인자에 대한 정보를 담고 있습니다.

이름타입필수 여부설명
nameFieldPath입력 필드의 고유한 이름입니다.
controlControlcontrol 객체는 useForm을 호출하여 얻을 수 있습니다. FormProvider를 사용할 때는 선택 사항입니다.
renderFunction이는 렌더 프로퍼티입니다. React 엘리먼트를 반환하는 함수로, 컴포넌트에 이벤트와 값을 연결할 수 있는 기능을 제공합니다. 이는 비표준 프로퍼티 이름을 가진 외부 제어 컴포넌트와의 통합을 단순화합니다. 자식 컴포넌트에 onChange, onBlur, name, ref, value를 제공하며, 특정 입력 상태를 포함하는 fieldState 객체도 제공합니다.
defaultValueunknown중요: useForm에서 defaultValue 또는 defaultValuesundefined를 적용할 수 없습니다.
  • 필드 레벨에서 defaultValue를 설정하거나 useFormdefaultValues를 설정해야 합니다. undefined는 유효한 값이 아닙니다.
  • 폼이 기본값으로 reset을 호출할 경우, useFormdefaultValues를 제공해야 합니다.
  • onChangeundefined로 호출하는 것은 유효하지 않습니다. 대신 null이나 빈 문자열을 기본값 또는 초기화 값으로 사용해야 합니다.
rulesObjectregister 옵션과 동일한 형식의 유효성 검사 규칙입니다. 여기에는 다음이 포함됩니다:

required, min, max, minLength, maxLength, pattern, validate
shouldUnregisterboolean = false`컴포넌트가 언마운트된 후 입력 필드가 등록 해제되고, defaultValues도 제거됩니다.

참고: 이 프로퍼티는 useFieldArray와 함께 사용할 때 피해야 합니다. 입력 필드가 언마운트/재마운트 및 재정렬된 후 unregister 함수가 호출되기 때문입니다.
disabledboolean = false`disabled 프로퍼티는 field 프로퍼티에서 반환됩니다. 제어된 입력 필드는 비활성화되며, 제출 데이터에서 해당 값이 제외됩니다.

반환값


아래 표는 Controller가 생성하는 속성에 대한 정보를 담고 있습니다.

객체 이름이름타입설명
fieldonChange(value: any) => void입력값을 라이브러리로 전달하는 함수입니다.

이 함수는 입력의 onChange prop에 할당되어야 하며, 값은 undefined가 아니어야 합니다.
이 prop은 formState를 업데이트하며, setValue나 필드 업데이트와 관련된 다른 API를 수동으로 호출하는 것을 피해야 합니다.
fieldonBlur() => void입력의 onBlur 이벤트를 라이브러리로 전달하는 함수입니다. 이 함수는 입력의 onBlur prop에 할당되어야 합니다.
fieldvalueunknown제어된 컴포넌트의 현재 값입니다.
fielddisabledboolean입력의 비활성화 상태입니다.
fieldnamestring등록된 입력의 이름입니다.
fieldrefReact.refhook form과 입력을 연결하기 위해 사용되는 ref입니다. 컴포넌트의 입력 ref에 ref를 할당하면 hook form이 오류가 발생한 입력에 포커스를 맞출 수 있습니다.
fieldStateinvalidboolean현재 입력의 유효하지 않은 상태입니다.
fieldStateisTouchedboolean현재 제어된 입력의 터치 상태입니다.
fieldStateisDirtyboolean현재 제어된 입력의 더티 상태입니다.
fieldStateerrorobject이 특정 입력에 대한 오류입니다.
formStateisDirtyboolean사용자가 어떤 입력을 수정한 후 true로 설정됩니다.
  1. 중요: useForm에서 모든 입력의 defaultValues를 제공해야 hook form이 폼이 더티인지 비교할 수 있는 단일 소스를 가질 수 있습니다.
  2. 파일 타입 입력은 파일 선택 취소와 FileList 객체 때문에 앱 레벨에서 관리되어야 합니다.
formStatedirtyFieldsobject사용자가 수정한 필드가 담긴 객체입니다. useForm을 통해 모든 입력의 defaultValues를 제공해야 라이브러리가 defaultValues와 비교할 수 있습니다.
  1. 중요: useForm에서 defaultValues를 제공해야 hook form이 각 필드의 더티 상태를 비교할 수 있습니다.
  2. 더티 필드는 isDirty formState로 표현되지 않습니다. 왜냐하면 더티 필드는 전체 폼이 아닌 필드 레벨에서 더티로 표시되기 때문입니다. 전체 폼 상태를 확인하려면 isDirty를 사용하세요.
formStatetouchedFieldsobject사용자가 상호작용한 모든 입력이 담긴 객체입니다.
formStatedefaultValuesobjectuseForm의 defaultValues 또는 reset API를 통해 업데이트된 defaultValues에 설정된 값입니다.
formStateisSubmittedboolean폼이 제출된 후 true로 설정됩니다. reset 메서드가 호출될 때까지 true로 유지됩니다.
formStateisSubmitSuccessfulboolean폼이 런타임 오류 없이 성공적으로 제출되었음을 나타냅니다.
formStateisSubmittingboolean폼이 현재 제출 중이면 true, 그렇지 않으면 false입니다.
formStateisLoadingboolean폼이 현재 비동기 기본값을 로드 중이면 true입니다.
중요: 이 prop은 비동기 defaultValues에만 적용됩니다.
formStatesubmitCountnumber폼이 제출된 횟수입니다.
formStateisValidboolean폼에 오류가 없으면 true로 설정됩니다.

setErrorisValid formState에 영향을 미치지 않으며, isValid는 항상 전체 폼 유효성 검사 결과에 따라 결정됩니다.
formStateisValidatingboolean유효성 검사 중이면 true로 설정됩니다.
formStateerrorsobject필드 오류가 담긴 객체입니다. 오류 메시지를 쉽게 가져올 수 있는 ErrorMessage 컴포넌트도 있습니다.

예제:


import ReactDatePicker from "react-datepicker"
import { TextField } from "@material-ui/core"
import { useForm, Controller } from "react-hook-form"
type FormValues = {
ReactDatepicker: string
}
function App() {
const { handleSubmit, control } = useForm<FormValues>()
return (
<form onSubmit={handleSubmit((data) => console.log(data))}>
<Controller
control={control}
name="ReactDatepicker"
render={({ field: { onChange, onBlur, value, ref } }) => (
<ReactDatePicker
onChange={onChange} // 값을 hook form으로 전송
onBlur={onBlur} // 입력이 터치/블러되었음을 알림
selected={value}
/>
)}
/>
<input type="submit" />
</form>
)
}
import React from "react"
import ReactDatePicker from "react-datepicker"
import { TextField } from "@material-ui/core"
import { useForm, Controller } from "react-hook-form"
function App() {
const { handleSubmit, control } = useForm()
return (
<form onSubmit={handleSubmit((data) => console.log(data))}>
<Controller
control={control}
name="ReactDatepicker"
render={({ field: { onChange, onBlur, value, ref } }) => (
<ReactDatePicker
onChange={onChange}
onBlur={onBlur}
selected={value}
/>
)}
/>
<input type="submit" />
</form>
)
}

React Native

Expo JS
import { Text, View, TextInput, Button, Alert } from "react-native"
import { useForm, Controller } from "react-hook-form"
export default function App() {
const {
control,
handleSubmit,
formState: { errors },
} = useForm({
defaultValues: {
firstName: "",
lastName: "",
},
})
const onSubmit = (data) => console.log(data)
return (
<View>
<Controller
control={control}
rules={{
required: true,
}}
render={({ field: { onChange, onBlur, value } }) => (
<TextInput
placeholder="First name"
onBlur={onBlur}
onChangeText={onChange}
value={value}
/>
)}
name="firstName"
/>
{errors.firstName && <Text>This is required.</Text>}
<Controller
control={control}
rules={{
maxLength: 100,
}}
render={({ field: { onChange, onBlur, value } }) => (
<TextInput
placeholder="Last name"
onBlur={onBlur}
onChangeText={onChange}
value={value}
/>
)}
name="lastName"
/>
<Button title="Submit" onPress={handleSubmit(onSubmit)} />
</View>
)
}

비디오


아래 비디오는 Controller의 내부 구조와 구현 방식을 보여줍니다.

TIP
  • MUI, AntD, Chakra UI와 같은 외부 제어 컴포넌트를 다룰 때는 각 prop의 역할을 이해하는 것이 중요합니다. Controller는 입력값을 보고하고 설정하는 "스파이" 역할을 합니다.

    • onChange: 데이터를 hook form으로 전송
    • onBlur: 입력이 상호작용되었음을 보고 (포커스와 블러)
    • value: 입력의 초기값과 업데이트된 값을 설정
    • ref: 오류 발생 시 입력에 포커스를 줄 수 있도록 함
    • name: 입력에 고유한 이름을 부여 아래 Codesandbox 예제를 참고하세요:
    • MUI 및 기타 컴포넌트
    • Chakra UI 컴포넌트
  • 입력을 다시 register하지 마세요. 이 컴포넌트는 등록 과정을 처리하도록 설계되었습니다.

    <Controller
    name="test"
    render={({ field }) => {
    // return <input {...field} {...register('test')} />; ❌ 중복 등록
    return <input {...field} /> // ✅
    }}
    />
  • onChange 중에 값을 변환하여 hook form으로 전송되는 값을 커스터마이즈할 수 있습니다.

    <Controller
    name="test"
    render={({ field }) => {
    // 문자열 대신 정수를 전송
    return (
    <input
    {...field}
    onChange={(e) => field.onChange(parseInt(e.target.value))}
    />
    )
    }}
    />

여러분의 지원에 감사드립니다

React Hook Form이 프로젝트에서 유용하다면, GitHub에서 스타를 눌러 지원해 주세요.