react-hook-from (controlled component, uncontrolled component 리렌더링)
react-hook-form 라이브러리를 접하게 되면서 장점 중 하나가 re-rendering이 적다는 것이었다. 이해하기 위해서는 controlled component, uncontrolled component 개념을 알게되었다. 입력을 받는 방법중 여러 입력을 다루는 form을 대표적이 예시로 내용을 작성하였다.
대표 Form
- 설문조사나 로그인등 개발을 하다보면 form을 많이 사용하게 된다. 보통 데이터를 입력받는 요소에 value와 onChange와 같은 변화를 감지하는 handler를 같이 넣어서 개발한다.
<form onSubmit={handleSubmit}>
<input type="text" value={name} onChange={(e)=>setName(e.target.value)}/>
</form>
- 이때 사용된 input은
controlled component
의 대표적인 예시이다.
controlled conponent : push
- HTML 엘리먼트에 들어온 정보를 prop으로 state를 변경시키고, 변경된 state를 기반으로 HTML 엘리먼트의 value를 변경시키는 방식이다.
class Form extends Component {
constructor() {
super();
this.state = {
name: "",
};
}
handleNameChange = (event) => {
this.setState({ name: event.target.value });
};
render() {
return (
<div>
<input type="text" value={this.state.name} onChange={this.handleNameChange} />
</div>
);
}
<form onSubmit={handleSubmit}>
<input type="text" value={name} onChange={(e)=>setName(e.target.value)}/>
</form>
controlled component
의 대표적인 예시이다.- HTML 엘리먼트에 들어온 정보를 prop으로 state를 변경시키고, 변경된 state를 기반으로 HTML 엘리먼트의 value를 변경시키는 방식이다.
class Form extends Component {
constructor() {
super();
this.state = {
name: "",
};
}
handleNameChange = (event) => {
this.setState({ name: event.target.value });
};
render() {
return (
<div>
<input type="text" value={this.state.name} onChange={this.handleNameChange} />
</div>
);
}
흐름을 살펴보면,
''
빈 비열로 시작a
입력, handleNameChange가 호출을 받는다.a
를 받고 setState를 부른다. input은 받은a
를 value로 가지고 re-render이 된다.b
를 입력하면 handleNameChange가 호출을 받는다.ab
를 가져와서 seState로 상태를 저장한다. input을ab
value를 가지고 re-render 된다.
이러한 흐름은 input의 value가 바뀔때 마다 값을 push
하기 때문에 요청할 필요없이 구성요소가 항상 현재 값을 갖게된다. 데이터와 입력은 항상 동기화된다.
예시
- 변경사항을 항상 받기 때문에 사용하기 유용한 경우가 있다.
- 검증과 같은 in-place 피드백
- 채워지지 않거나 유효하지 않은 필드가 있을떄 버튼의 비활성화
- 신용카드 번호와 같은 특정입력이 강화된 형식
input뿐 아니라 다른 controlled component가 있다.
문제점
- 한 두개의 입력이 있다면 value와 handler로 간단하게 데이터를 감지할수 있지만 복잡해질 수록 코드의 양은 늘어나고 상태를 공유하기 위한 노력이 늘어난다. 컴포넌트의 재사용성도 어려워진다.
uncontrolled component : pull
- input의 value가 DOM에 저장된다. controlled component와 반대로 state와 hanlder 대신에
ref
를 이용해 DOM에 접근한다.
const NameForm = () => {
const inputRef = useRef<HTMLInputElement>(null);
function handleSubmit(event) {
alert('A name was submitted: ' + inputRef.current.value);
}
return (
<form onSubmit={handleSubmit}>
<label>
Name:
<input type="text" ref={inputRef} />
</label>
<input type="submit" value="Submit" />
</form>
)
}
- input의 변경을 계속 관찰하지 않고 필요한 시점에 ref의 값을 읽어
pull
하는 방식이다.
여기까지 두 component의 특징을 이해했다면 하단에 나올 react-hook-compont의 특징을 좀더 이해하기 쉬울 것 같다.
react-hook-form
ref
를 이용해 DOM에 접근한다.const NameForm = () => {
const inputRef = useRef<HTMLInputElement>(null);
function handleSubmit(event) {
alert('A name was submitted: ' + inputRef.current.value);
}
return (
<form onSubmit={handleSubmit}>
<label>
Name:
<input type="text" ref={inputRef} />
</label>
<input type="submit" value="Submit" />
</form>
)
}
pull
하는 방식이다. 여기까지 두 component의 특징을 이해했다면 하단에 나올 react-hook-compont의 특징을 좀더 이해하기 쉬울 것 같다.
react-hook-form은 Uncontrolled component의 방식을 활용한 라이브러리이다.
유명한 form 라이브러리중 하나인 formik과 비교한 표.
장점
1. 간결한 코드 (regster,watch 등의 기능을 통해 코드양을 줄일 수 있다.)
2. 적은 용량
3. 자식 컴포넌트 리렌더링 방지 (uncontrolled component의 특징)
4. 렌더링 최소화 (uncontrolled component의 특징2)
5. 빠른 마운트 속도
import { useState } from "react";
import { useForm } from "react-hook-form";
import Header from "./Header";
export function App() {
const { register, handleSubmit } = useForm();
const [data, setData] = useState("");
return (
<form onSubmit={handleSubmit((data) => setData(JSON.stringify(data)))}>
<Header />
<input {...register("firstName")} placeholder="First name" />
<select {...register("category")}>
<option value="">Select...</option>
<option value="A">Option A</option>
<option value="B">Option B</option>
</select>
<textarea {...register("aboutYou")} placeholder="About you" />
<p>{data}</p>
<input type="submit" />
</form>
);
}
위의 개념을 알기 전 장점을 읽었을 때는 와닿지않았다. 하지만 component의 개념을 이해하고 다시 장점을 읽으니 라이브러리의 필요성 및 내세우는 장점의 이유를 알 수 있었다.
실제 사용 사례
-
사이프 프로젝트에서
select
,input
,textarea
,file
의 데이터를 받아야 하는 기능에 react-hook-form을 적용해봤다.
setValue,watch 기능을 추가로 사용하였다. -
특히 이미지 부분에서 많은 시간이 들었다. 이미지가 들어간 배열을 watch로 관찰하고 setValue로 자식 컴포넌트의 값을 받아 반영시켜주었다,
<ImageLayout>
{Array.from({ length: 5 }).map((item, idx) => {
return (
<AddCommunityImage
ref={inputRef}
key={idx}
pk={idx}
data={watchUploadImages[idx]}
imageList={watchUploadImages}
dispatch={(v: Image[]) => setValue("uploadImages", v)}
/>
);
})}
</ImageLayout>
완료 버튼을 누르면 입력한 데이터들이 key : value로 묶여 나온걸 확인할 수 있다.
reference
https://so-so.dev/react/form-handling/
https://goshacmd.com/controlled-vs-uncontrolled-inputs-react/
https://mysterico.tistory.com/9
https://soldonii.tistory.com/145
Author And Source
이 문제에 관하여(react-hook-from (controlled component, uncontrolled component 리렌더링)), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@wjd489898/react-hook-from-controlled-component-uncontrolled-component-리렌더링저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)