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>
    );
  }

흐름을 살펴보면,

  • '' 빈 비열로 시작
  • a 입력, handleNameChange가 호출을 받는다. a를 받고 setState를 부른다. input은 받은 a를 value로 가지고 re-render이 된다.
  • b 를 입력하면 handleNameChange가 호출을 받는다. ab를 가져와서 seState로 상태를 저장한다. input을 ab value를 가지고 re-render 된다.

이러한 흐름은 input의 value가 바뀔때 마다 값을 push하기 때문에 요청할 필요없이 구성요소가 항상 현재 값을 갖게된다. 데이터와 입력은 항상 동기화된다.

예시

  • 변경사항을 항상 받기 때문에 사용하기 유용한 경우가 있다.
  1. 검증과 같은 in-place 피드백
  2. 채워지지 않거나 유효하지 않은 필드가 있을떄 버튼의 비활성화
  3. 신용카드 번호와 같은 특정입력이 강화된 형식

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

https://react-hook-form.com/

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

좋은 웹페이지 즐겨찾기