목차
1. 하나의 Form에 여러개의 공통된 Input을 쓴다면?
컴포넌트 팡인 우리 조🧚🏻 답게 이미 귀여운 inpiut 디자인까지 다 뽑아두었건만!!!
react-hook-form
을 쓰면 내가 만들어둔 귀여운 디자인의 Input을 못쓰는 거 아닌가!? 인라인 스타일로 css 다 다시 박아넣으라구?!!? 당장 재.활.용 내놔. 라고 생각할 때 아주 소중한 글을 발견했다.
바로 useController
라는 훅을 사용하면 내 입맛대로 custom이 가능하다는 것!!
자세한 것은 공식문서를 참고하면서 진행하겠습니다.


2. Use Controller 맛보기
2-1. 파라미터
먼저 useController
가 사용하는 props(즉 파라미터로 받는 객체들) 는 Controller 와 같다.
Name | Type | Option |
name | FieldPath | |
control | Control | react-hook-form의 일부로 제어할 수 있도록 넣어주는 개체 |
rules | Object |
그 외에도 defaultValue
나 shouldUnregister
가 있다. 자세한 사항은 공식문서를 참고하면 좋을 것 같다.
특히 defaultValue
사용 시에 값을 제공한다면 반드시 useForm에 defaultValue를 넣어서 undefined를 만들지 않도록 해야한다.
2-2. 리턴해주는 객체
리턴해주는 속성에는 크게 3가지가 있다.
field
fieldState
formState
먼저 field
에는 input에 직접적으로 들어가는 value, name, onChange 가 담겨있다.
fieldState
는 invalid, isTouched, error 등 해당 필드의 상태를 관리한다. 또 onBlur나 ref 속성도 사용할 수 있어서 컴포넌트 작업할 때 편리하게 필드를 관리할 수 있다.
(onBlur는 Input창을 선택하지 않았을 때, 즉 focus의 반대상황일 때 실행되는 이벤트)
3. 이제 진짜 사용해보자 컨트롤러
재활용하고 싶은 Input 컴포넌트를 만들어보자.
중간에 rules
에 있는 Omit< A, B> 부분은 A 라는 타입에서 B 속성을 제외한 interface를 사용한다고 이해하면 된다. 제네릭타입에 대한 자세한 설명은 여기를 클릭하자
코드 예시보기 ( 재활용할 컴포넌트 이름 : InputForm.tsx)
src/components/Input/InputForm.tsx import { Control, FieldPath, FieldValues, RegisterOptions, useController, useForm, } from 'react-hook-form'; export type TControl<T extends FieldValues> = { control: Control<T>; name: FieldPath<T>; rules?: Omit< RegisterOptions<T>, 'valueAsNumber' | 'valueAsDate' | 'setValueAs' | 'disabled' >; }; function InputForm({ control, name, rules }: TControl<any>) { const { field: { value, onChange }, } = useController({ name, rules, control }); return <input className="input" value={value} onChange={onChange} />; } export default InputForm;
이제 내가 필요한 곳에 가져와서 사용하면 된다!
코드 예시보기
src/pages/LoginPage import InputForm from '@/components/Inputs/Input/InputForm'; import { useForm, SubmitHandler } from 'react-hook-form'; // typescript이기 때문에 interface를 지정해줘야 한다. interface IFormInput { firstName: String; } function LoginPage() { const { control, handleSubmit, formState: { errors }, } = useForm<IFormInput>(); const onSubmit: SubmitHandler<IFormInput> = (data) => console.log(data); return ( <form onSubmit={handleSubmit(onSubmit)}> <InputForm name="firstName" control={control} rules={{ required: true }} /> <p>{errors.firstName && 'First name is required'}</p> <input type="submit" /> </form> ); export default LoginPage;
결과는?
두구두구두구……

먼저 required:true
를 적용했기 때문에, 빈칸을 submit하면 input 창 아래에 에러메세지가 나온다.

반대로 input 창에 Harim이라고 제출하면 console 창에 보면 아름답게 잘 실행됨을 확인할 수 있다.
4. Tailwind를 사용해서 더 아름답게 디자인하기
참고한 글


Uploaded by N2T