React Hook Form 이용해서 MUI 컴포넌트 제어하기

🌊·2023년 5월 29일
0

React

목록 보기
20/20
post-thumbnail

개요

오늘은 React Hook Form 라이브러리를 이용해서 MUI와 같은 UI 라이브러리 컴포넌트를 제어하는 방법을 같이 나눠보려고 합니다.

우선 React Hook Form 라이브러리에 대한 개념 없이 MUI 컴포넌트를 제어하는 방법을 찾기까지 너무 힘들었습니다.. 💩

대부분의 포스팅에서는 register를 이용해서 input과 같은 컴포넌트를 제어하는 방법을 알려주고 있었는데요.
MUI에 적용하기에는 맞지 않는 방법이었고, 제 문제에 대한 해답을 찾기 위해서 굉장히 많은 시간을 사용했습니다. 😢

제가 출처에 남긴 포스팅의 방식을 찾는데 오래 걸린 것은 아니지만.. 문제에 대한 해결 방법이라는 것을 아는데 오래 걸렸던 것 같습니다.. ㅎㅎ

1. Controller 사용하기

React Hook Form 라이브러리에서 제공하는 컴포넌트로, 외부 컴포넌트를 React Hook Form과 연결하여 제어하는데 사용됩니다.

Controller 기능

  • 외부 컴포넌트 연결: 외부 컴포넌트를 연결해서 필드를 제어할 수 있습니다.
    값을 추적하거나 입력을 관리할 수 있습니다.
  • 컴포넌트 속성 설정: name, onChange와 같은 속성을 외부 컴포넌트에 전달하여 필드의 상태를 업데이트 할 수 있습니다.
  • 유효성 검증 규칙 설정: rules 속성을 사용하여 필드에 대한 유효성 검사 규칙을 정의할 수 있습니다.
    유효성 검사는 자동으로 진행됩니다.
import { useForm, Controller } from 'react-hook-form';
import { TextField } from '@mui/material';

const MyForm = () => {
	const { control, handleSubmit } = useForm();
	const onSubmit = (data) => console.log(data);

	return (
		<form onSubmit={handleSubmit(onSubmit)}>
			<Controller
				name='name'
				control={control}
				rules={{ required: true }}
				render={({ filed }) => (
					<TextField
						label='name'
						{...field}
					/>
				)}
		</form>
	)
}

render 속성에서 렌더링할 컴포넌트를 정의하고 field 속성을 전달해서 해당 컴포넌트 제어를 React Hook Form에게 위임할 수 있습니다.

2. useController 사용하기

이전에 사용한 Controller 컴포넌트와 동일한 권한을 가지는 커스텀 훅입니다.
추가적으로 Controller와 동일한 propsmethod를 사용할 수 있습니다.

useController는 재사용 가능한 컴포넌트를 만드는데 유용합니다.

공식문서

import { useForm, useController, UseControllerProps } from "react-hook-form";

type FormValues = { FirstName: string; };

function Input(props: UseControllerProps<FormValues>) {
	const { field, fieldState } = useController(props);
	return (
		<div>
			<input {...field} placeholder={props.name} />
		</div>
	);
};

export default function App() {
	const { handleSubmit, control } = useForm<FormValues>({
		defaultValues: {
			FirstName: ""
		},
		mode: "onChange"
	})
	const onSubmit = (data: FormValues) => console.log(data)

return (
	<form onSubmit={handleSubmit(onSubmit)}>
		<Input control={control} name='FirstName' rules={{ required: true }} />
	</form>
	)
}

위의 코드와 비교했을 때, Controller 컴포넌트를 사용하지 않고, 별도로 정의한 Input 컴포넌트를 제어할 수 있습니다.

하지만 예제에서는 특정 타입에서만 사용할 수 있도록 되어 있기 때문에 이 부분을 제너릭을 활용해서 공통 컴포넌트로 사용할 수 있도록 바꿔줘야 합니다.
추가적으로 별도로 정의한 Input 컴포넌트에 MUI 컴포넌트인 textField를 사용할 수 있지만, textfieldProps를 제대로 넘겨주지 못할 것입니다.

useController + Mui Text Field

interface MuiProps {
	textFieldProps?: TextFieldProps;
}

const Input = <
	TFieldValues extends FieldValues = FieldValues,
	TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>
>({
	textFieldProps,
	...props
}): MuiProps & UseController<TfieldValues, TName>) => {
	const { field, fieldState: { error } } = useController(props)

	return (
		<TextField
			{...textFieldProps}
			{...field}
			error={!!error}
			helperText={!!error && error.message}
		/>
	)
}

사용

const App = () => {
	const { control, handleSubmit } useForm()

	const onSubmit = (data) => console.log(data)

	return (
		<form onSubmit={handleSubmit(onSubmit)}>
			<Input
				name="FirstName"
				control={control}
				rules={{ required: true }}
				textFIeldProps={{
					label: "First Name"
				}}
		</form>
	)
}

개인적으로 Controller 컴포넌트를 사용하는 것보다 깔끔하고 편하다고 생각합니다.

추가적으로, 마지막의 useControllerMUItextField 컴포넌트를 같이 사용하는 방식은 제가 참고한 포스팅에 훨씬 자세한 설명이 있으니 원문을 참고하시는 것도 좋을 것 같습니다! 🙏🙇‍♂️

만약 저처럼 React Hook Form 라이브러리와 MUI를 같이 사용하고 싶다면, 결국 TextFieldProps를 별도로 처리해줘야 합니다!
1. Controller 컴포넌트 활용하기
2. useController 훅 활용하기
가독성이나 선호도 차이에 따라 위의 2가지 방법 중 선택해서 사용하면 될 것 같습니다!
저의 경우에는 useController 훅을 활용해서 별도로 정의한 Input 컴포넌트를 만들었습니다!

마무리

개인적으로 이번 학습에 처음으로 챗 GPT를 많이 사용한 것 같습니다..
이전까지는 아직 챗 GPT를 믿을 수 없다는 생각이 많이 있어서 전혀 사용하지 않았는데요.
시간도 부족하고 막막한 느낌이 있어서 사용했더니.. 저에게 좋은 경험을 준 것 같습니다. 👍

그리고 React Hook Form의 공식문서는 너무나도 잘 되어있다는 생각이 들었습니다.
처음부터 공식문서를 살펴 볼 시간이 있었다면.. 오히려 더 빠르게 해결 할 수 있지 않았을까? 라는 생각이 들었네요!

  • 해결의 결정타를 날려준 포스팅 주인님 🙏
  • 정보의 중심이 되는 공식문서 📚
  • 나의 시간을 많이 아껴준 챗GPT ⚙️

삼박자가 잘 맞는 아주 값진 경험이었습니다..⭐️

출처

0개의 댓글