개발

React-hook-form이 없는 Form Data관리

배우겠습니다 2024. 8. 15. 17:37
import React, { useState, useRef } from 'react';
import { FormDataType } from "./types";

const Form = () => {

  const [formData,setFormData] = useState<FormDataType>({name:})
  const handleSubmit = (e) => {
    e.preventDefault();

  };

  return (
    <form onSubmit={handleSubmit}>
      <div>
        <label>Name:</label>
        <input
          type="text"
          name="name"
        />
      </div>
      <div>
        <label>Email:</label>
        <input
          type="email"
          name="email"
        />
      </div>
      <button type="submit">Submit</button>
    </form>
  );
};

export default Form;

이 Form을 여러 방식으로 관리해보자!

useState

import React, { useState } from 'react';
import { FormDataType } from "./types";

const Form = () => {
  const [formData,setFormData] = useState<FormDataType>({name:"",email:""});
  const handleSubmit = (e) => {
    e.preventDefault();
    submitFetch(formData);
  };
  // 1
  const handleNameChange = (e) => {
    setFormData(...formData,name:e.target.value);
  };
  const handleEmailChange = (e) => {
    setFormData(...formData,email:e.target.value);
  };
  // 2
  const handleChange = (e) => {
    const { name, value } = e.target;
    setFormData({
      ...formData,
      [name]: value,
    });
  };


  return (
    <form onSubmit={handleSubmit}>
      <div>
        <label>Name:</label>
        <input
          type="text"
          name="name"
          value={formData.name}
          onChange={handleNameChange}
        />
      </div>
      <div>
        <label>Email:</label>
        <input
          type="email"
          name="email"
          value={formData.email}
          onChange={handleEmailChange}
        />
      </div>
      <button type="submit">Submit</button>
    </form>
  );
};

export default Form;
  • 가장 기본적인 관리
  • input을 조작할때 마다 폼 전체의 리랜더링 발생 -> 낭비
  • 데이터 변화시 불변성을 고려한 갱신으로 인한 코드 가독성 감소
    • 각 필드의 상태를 각각의 상태로 관리할 수 있으나, 오히려 유지보수 및 코드의 양 차원 문제에서 문제 발생
    • 근본적 원인(랜더링 방지) 해결 불가
  • 복잡한 form은 props drilling 발생

    useRef (1)

    import React, { useState } from 'react'; import { FormDataType } from "./types";`
    const Form = () => {  
    const formDataRef = useRef({name:"",email:""});  
    const handleSubmit = (e) => {  
    e.preventDefault();  
    submitFetch(formDataRef.current);  
    };  
    const handleNameChange = (e) => {  
    formDataRef.current.name = e.target.value;  
    };  
    const handleEmailChange = (e) => {  
    formDataRef.current.emil = e.target.value;  
    };
    
    

return (












);
};

export default Form;

* 코드가 useState에 비해 훨씬 더 간단화(코드양, 데이터갱신로직)
* Ref를 통한 랜더링 낭비 방지
* 복잡한 form의 경우의 Props Drilling은 해결 못함
## useRef (2)
```typescript
import React, { useState } from 'react';
import { FormDataType } from "./types";

const Form = () => {
  const formRef = useRef<null | HTMLFormElement>(null);
  const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
    e.preventDefault();
    if (formRef.current) {
      const formData = new FormData(formRef.current);
      // If send the formData with multipart/form-data content-type
      submitFetch(formData);
      // If send the formData with application/json content-type
      const data: FormDataType = {
        name: formData.get('name') as string,
        email: formData.get('email') as string,
      };
      submitFetch(data);
    }
  };

  return (
    <form onSubmit={handleSubmit} ref={formRef}>
      <div>
        <label>Name:</label>
        <input
          type="text"
          name="name"
        />
      </div>
      <div>
        <label>Email:</label>
        <input
          type="email"
          name="email"
        />
      </div>
      <button type="submit">Submit</button>
    </form>
  );
};

export default Form;
  • 코드가 매우 간단
  • new FormData(HTMLFormElement)는 내부 input tag들의 input name:input value 형식의 formData를 반환한다는 것을 이용
  • props drilling 해결
  • 커스터마이징시 이전 방식에 비해 더 복잡한 로직 필요 -> 간단한 form에 적합
  • type safety는 떨어지는 느낌(감수하거나 보장하기 위한 추가로직 필요 가능성)

총평

react-hook-form이 닭잡는데 소잡는 칼을 쓰는 느낌이라면 난 이런 스타일로 개발하는 것 같다

  1. 폼이 매우 간단
  • useRef (2) 사용, 경험상 어떤 방법보다 제일 빠르고 쉬운 개발
  1. 매우 간단하진 않음
  • useRef (1) 사용, ref을 contextAPI로 providing해 propsdrilling 문제를 부분해결
  1. 제어를 해야하는 경우 ex 미리보기가 지원되는 프로필 이미지 변경 폼
  • useRef (1) + 별도 상태 지정 또는 폼이 거대하지 않아 랜더링 낭비되도 병목이 심하지 않을 것 같다면 useState 사용결론사실 이 포스트를 본다면, react-hook-form의 내부 동작에 실마리가 될 수 있을 것이라 기대된다.
    가장 간단한 useRef (2)의 문제(구현하지 못하는 기능, 데이터 처리 등)가 무엇인지?
    이를 위해 useRef (1)을 어떻게 사용하면 좋을지?
    제어 컴포넌트 사용이 강제되는데 랜더링 최적화도 하고싶다면 어떻게 useState를 useRef와 연계해 지혜롭게 사용할지?
    그렇게해서 react-hook-form을 무조건 써야하고 form마다 써야하는지?