Controller 컴포넌트를 사용해서 처리를 하고 나니 중복된 코드가 많아 개선 할 수 있을 것 같다는 생각이 들었다.
찾아보니 useController 를 사용해서 재사용이 가능한 컴포넌트를 만들 수 있다고 해서 바로 시도! 😎
코드를 보기 전에 useController의 Props 부분부터 확인해보자!
// controller.d.ts
export type UseControllerProps<TFieldValues extends FieldValues = FieldValues, TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>> = {
name: TName;
rules?: Omit<RegisterOptions<TFieldValues, TName>, 'valueAsNumber' | 'valueAsDate' | 'setValueAs' | 'disabled'>;
shouldUnregister?: boolean;
defaultValue?: FieldPathValue<TFieldValues, TName>;
control?: Control<TFieldValues>;
disabled?: boolean;
};
🗸 name - input 의 고유 이름으로 필수값이다.
🗸 control - useForm을 호출하면 제공되는 컨트롤 객체이다.
🗸 defaultValue - 기본값 세팅을 위해서 사용한다.
주의) defaultValue를 사용하는 경우 반드시 useForm에 defaultValue를 세팅해줘야한다!
🗸 rules - 유효성 검사 규칙.
rules에는 required, min, max, minLength, maxLength, pattern, validate가 포함되어있다.
🗸 shouldUnregister - 사용하게 되면 unmount 이후 resgister이 등록 취소되고 defaultValues도 제거된다.
참고로 Return 부분은 이런식으로 정의되어있다.
// controller.d.ts
export type UseControllerReturn<TFieldValues extends FieldValues = FieldValues, TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>> = {
field: ControllerRenderProps<TFieldValues, TName>;
formState: UseFormStateReturn<TFieldValues>;
fieldState: ControllerFieldState;
};
나는 타입스크립트를 사용했는데, 타입을 잡아주는 부분에서 시간이 꽤 걸렸다. 😨😨
// InputText.tsx 타입 선언 부분
type TControl<T extends FieldValues> = {
control: Control<T>;
name: FieldPath<T>;
rules?: Omit<
RegisterOptions<T>,
'valueAsNumber' | 'valueAsDate' | 'setValueAs' | 'disabled'
>;
};
type TProps<T extends FieldValues> = TextFieldProps & TControl<T>;
나머지 부분은 아래와 같이 구현했는데,
설명을 좀 하자면 재사용 가능한 컴포넌트이니 공통적으로 쓰일 스타일과 속성에 맞게 세팅해주었다.
// InputText.tsx
const InputText = <T extends FieldValues>({
name,
rules,
control,
...props
}: TProps<T>) => {
const {
field: { value, onChange },
fieldState: { isDirty, isTouched, error },
} = useController({
name,
rules,
control,
});
return (
<CustomTextField
variant="outlined"
fullWidth
name={name}
value={value}
onChange={onChange}
error={Boolean(error)}
helperText={error?.message}
{...props}
/>
);
};
// form.tsx
<form onSubmit={handleSubmit(onSubmit)}>
// 이름을 입력받는 부분
<InputText
control={control}
name="name"
rules={{
required: '값을 입력해주세요',
validate: (value) =>
isValidName(value) || '한글, 영어, 공백만 입력 가능 합니다.',
}}
/>
// 이메일을 입력받는 부분
<InputText
control={control}
name="email"
rules={{
required: '값을 입력해주세요',
validate: (value) =>
isValidEMail(value) || '메일 주소를 확인해주세요.',
}}
/>
</form>
이전에 모기업 과제 전형을 진행하면서 form을 핸들링 할 때 Controller를 사용해서 처리를 했었는데
중복된 코드도 너무 많고, 지저분해보여서 아쉬움이 많이 남았던 기억이 있다. 😭
시간이 부족해서 개선을 하지 못한 채 제출했지만 꼭 개선해봐야겠다고 생각했었다.
이번에 시간을 내서 시도를 해봤는데 여유를 가지고 시도를 해서 그런지 저번보단 훨씬 더 수월한 느낌..!
(지난번엔 급하게 시도했다가 싹 걷어냈었음😭😭)
개인적으로 Controller를 사용하는 것보단 useController를 사용해서 재사용이 가능한 컴포넌트로 개발하는 방향이 더 나은 것 같다.
중복된 코드도 줄일 수 있고, form쪽 코드의 양을 줄일 수 있어 가독성 측면에서 훨씬 낫다고 느꼈다. 😇
react-hook-form은 장점이 많은 만큼 실제로 많은 곳에서 쓰인다고 한다.
내가 사용한 기능 말고도 유용한 기능이 굉장히 많으니 앞으로 조금씩 도장깨기를 해봐야겠다!
이전글
2023.12.14 - [Programming/React.js] - [react-hook-form] MUI와 함께 사용하기(Controller를 곁들인...)
Reference
https://www.react-hook-form.com/api/usecontroller/
https://tech.osci.kr/react-hook-form-with-mui/
[React] Portal이란?(w. 모달 구현) (1) | 2024.02.02 |
---|---|
리액트 프로젝트에 구글 애널리틱스 적용하기(react-ga4 사용) (0) | 2024.01.17 |
[react-hook-form] MUI와 함께 사용하기(Controller를 곁들인...) (0) | 2023.12.14 |
[React] Warning: Each child in a list should have a unique"key"prop 해결법 (0) | 2023.08.30 |
상태 관리 라이브러리 - React-Query (0) | 2023.07.04 |
댓글 영역