[TIL/React-Hook-Form] 2024/07/09
reference:1) https://www.react-hook-form.com/api/usecontroller/controller2) https://legacy.reactjs.org/docs/render-props.html✅ React-Hook-Fo
reference: 1) https://www.react-hook-form.com/api/usecontroller/controller 2) https://legacy.reactjs.org/docs/render-props.html
✅ React-Hook-Form 공식문서 톺아보기
6. Integrating with UI libraries ✍️
import Select from "react-select";
import { useForm, Controller } from "react-hook-form";
import Input from "@material-ui/core/Input";
const App = () => {
const { control, handleSubmit } = useForm({
defaultValues: {
firstName: '',
select: {}
}
});
const onSubmit = data => console.log(data);
return (
<form onSubmit={handleSubmit(onSubmit)}>
<Controller
name="firstName"
control={control}
render={({ field }) => <Input {...field} />}
/>
<Controller
name="select"
control={control}
render={({ field }) => <Select
{...field}
options={[
{ value: "chocolate", label: "Chocolate" },
{ value: "strawberry", label: "Strawberry" },
{ value: "vanilla", label: "Vanilla" }
]}
/>}
/>
<input type="submit" />
</form>
);
};외부 UI 라이브러리와 React Hook Form을 어떻게 통합해야 하는지 설명하는 section이다.
Controller 컴포넌트를 사용하면, 외부 UI 라이브러리의 요소의 registration process를 잘 수행할 수 있다고 설명하고 있다.
아래의 코드가 본 section의 핵심이다. 하지만 공식 문서의 Get Started 파트에서는 피상적인 사용법만 다루고 있기에, Controller Component의 더 깊은 내용을 확인해야 했다.

external controlled component와 쉽게 통합하기 위해 사용하는 'Wrapper Component'임을 명시하고 있다.

render props가 핵심인데, render는 컴포넌트에 event와 value를 연결할 수 있는 기능을 제공한다. 자식 컴포넌트에 onChange, onBlur, name, ref, value를 제공하며, 특정 '입력 상태'를 포함하는 fieldState 객체도 제공한다.
render의 type은 'Function'이다. 그런데 ```render={({ field }) => <Input {...field} />}``` 부분이 솔직히 잘 이해가 되지 않았다. 이유를 알아보니, render props가 무엇인지 몰라서 그랬던 것이었다.(React 공식 문서 읽어야 한다는 뜻.)
'render prop'은 함수이고, Controller 컴포넌트에 의해 호출되도록 내부적으로 구현이 되어있다. field 객체를 포함한 다양한 인자를 받을 수 있는 함수인데, 위 코드에서는 field를 구조 분해 할당을 통해 추출한다. 이때, field 객체는 Controller 컴포넌트에 의해 자동으로 제공되는 'form field와 관련된 상태와 메서드'를 포함한다. 이렇게 추출한 field 객체를 하위 컴포넌트(MUI Component 같은)에 전달하여 외부 컴포넌트 요소가 form field의 상태와 상호작용할 수 있게 되는 것이다.

과거 React doc을 살펴보니 커스텀 훅으로 대체되었다고 한다. 예전 공식 문서에서 설명하는 것처럼, render prop은 react 컴포넌트 간에 코드를 공유하기 위한 기법인데, custom hook의 존재 이유와 정확히 일치하기 때문이다. custom hook의 시초 같은 느낌이다.
## 7. Integrating Controlled Inputs ✍️
import { useForm, Controller } from "react-hook-form"; import { TextField, Checkbox } from "@material-ui/core";
function App() { const { handleSubmit, control, reset } = useForm({ defaultValues: { checkbox: false, } }); const onSubmit = data => console.log(data);
return (
); }
계속 공식 문서를 읽다 보니, Controlled component와 Uncontrolled component가 핵심이라는 생각이 든다.
Controlled component는 React의 상태(state)에 의해 값이 제어됨을 의미한다. 한마디로, 사용자가 입력 form을 조작할 때마다 React 상태가 업데이트되며, 이에 따라 UI가 리렌더링 된다는 뜻이다.
이에 반해, Uncontrolled component는 상태에 의존하지 않고 DOM 요소의 ref를 통해 값에 접근한다. 사용자의 입력에 따라 DOM 요소의 값이 변화할지언정, React의 상태는 이를 추적하지 않기에, 렌더링이 일어나지 않아 렌더링을 최적화할 수 있다는 장점을 갖는다.
각각의 장단점이 분명하겠지만, 사용자로부터 많은 정보를 입력받을 경우에는 불필요한 리렌더링을 최적화하는 것이 좋고, 이것이 React Hook Form의 가장 본질적인 컨셉인 것이다.
import React, { useState } from "react"; // React와 useState 훅을 import합니다. import ReactDOM from "react-dom"; // ReactDOM을 import합니다. import { useForm, Controller } from "react-hook-form"; // react-hook-form에서 useForm과 Controller를 import합니다. import Header from "./Header"; // Header 컴포넌트를 import합니다. import ReactDatePicker from "react-datepicker"; // react-datepicker 컴포넌트를 import합니다. import NumberFormat from "react-number-format"; // react-number-format 컴포넌트를 import합니다. import ReactSelect from "react-select"; // react-select 컴포넌트를 import합니다. import Mui from "./Mui"; // Mui 컴포넌트를 import합니다. import ButtonsResult from "./ButtonsResult"; // ButtonsResult 컴포넌트를 import합니다. import DownShift from "./DownShift"; // DownShift 컴포넌트를 import합니다. import AntD from "./AntD"; // AntD 컴포넌트를 import합니다. import DraftExample from "./DraftExample"; // DraftExample 컴포넌트를 import합니다. import { EditorState } from "draft-js"; // draft-js의 EditorState를 import합니다. import InputMask from "react-input-mask"; // react-input-mask 컴포넌트를 import합니다. import Chakra from "./Chakra"; // Chakra 컴포넌트를 import합니다. import "react-datepicker/dist/react-datepicker.css"; // react-datepicker의 CSS 파일을 import합니다. import "antd/dist/antd.css"; // antd의 CSS 파일을 import합니다. import "./styles.css"; // 스타일 CSS 파일을 import합니다.
let renderCount = 0; // 렌더링 횟수를 저장하는 변수를 초기화합니다.
const defaultValues = { Native: "", // Native 입력 필드의 기본값을 설정합니다. TextField: "", // TextField 입력 필드의 기본값을 설정합니다. Select: "", // Select 입력 필드의 기본값을 설정합니다. ReactSelect: { value: "vanilla", label: "Vanilla" }, // ReactSelect 컴포넌트의 기본 선택값을 설정합니다. Checkbox: false, // Checkbox 입력 필드의 기본값을 설정합니다. switch: false, // switch 입력 필드의 기본값을 설정합니다. RadioGroup: "", // RadioGroup 입력 필드의 기본값을 설정합니다. numberFormat: 123456789, // numberFormat 입력 필드의 기본값을 설정합니다. AntdInput: "Test", // AntdInput 입력 필드의 기본값을 설정합니다. AntdCheckbox: true, // AntdCheckbox 입력 필드의 기본값을 설정합니다. AntdSwitch: true, // AntdSwitch 입력 필드의 기본값을 설정합니다. AntdSlider: 20, // AntdSlider 입력 필드의 기본값을 설정합니다. AntdRadio: 1, // AntdRadio 입력 필드의 기본값을 설정합니다. downShift: "apple", // downShift 입력 필드의 기본값을 설정합니다. ReactDatepicker: new Date(), // ReactDatepicker 컴포넌트의 기본 날짜값을 설정합니다. AntdSelect: "", // AntdSelect 입력 필드의 기본값을 설정합니다. DraftJS: EditorState.createEmpty(), // DraftJS 에디터의 기본 상태를 설정합니다. MUIPicker: new Date("2020-08-01T00:00:00"), // MUIPicker 컴포넌트의 기본 날짜값을 설정합니다. country: { code: "AF", label: "Afghanistan", phone: "93" }, // country 객체의 기본값을 설정합니다. ChakraSwitch: true, // ChakraSwitch 입력 필드의 기본값을 설정합니다. reactMaskInput: "" // reactMaskInput 입력 필드의 기본값을 설정합니다. };
function App() { const { handleSubmit, reset, setValue, control } = useForm({ defaultValues }); // useForm 훅을 사용하여 폼 상태를 초기화하고 제어할 수 있는 객체들을 가져옵니다. const [data, setData] = useState(null); // data 상태와 setData 함수를 useState 훅을 통해 초기화합니다. renderCount++; // 렌더링 횟수를 증가시킵니다.
return (
); }const rootElement = document.getElementById("root"); ReactDOM.render(
More to read
Amazon VPC Architecture 이해하기
새로운 프로젝트를 기획하며, 개발에서 무엇을 가장 먼저 고민해야 하는지 다시 돌아보게 되었습니다.한때는 프론트엔드가 모든 설계의 출발점이라고 믿었습니다. 유저가 무엇을 보고, 어떤 흐름에서 머무르고 이탈하는지에 대한 이해 없이 서비스를 만든다는 건 불가능하다고 생각했기
'원사이트'프론트엔드 관점으로 알고리즘 이해하기
오랜만에 방법론에 관한 글을 쓰게 되었습니다. 최근 상황은 이렇습니다. SSAFY에서는 하루에 엄청난 양의 알고리즘 문제들을 과제로 수행하게 됩니다. 그 과정에서, '구현력'이 매우 떨어진다는 생각이 들었습니다. 완전히 어려운 문제라면 '아쉬움'이라는 감정조차 느끼지
SubnetVPC 설계의 시작: IP와 Subnet
반복되는 루틴 속에서 얻은 안정감을 발판 삼아, 이제는 기술적 스펙트럼을 넓히기 위한 개인 프로젝트에 착수하고자 합니다.이번 프로젝트의 목표는 단순한 포트폴리오 구축을 넘어, 실제 서비스 수준의 블로그 시스템 구현과 다국어 처리 적용 등 실무에 가까운 역량을 한 단계