라이브러리/React Hook Form

[React Hook Form] FormProvider, useFormContext로 중복 코드 없이 깔끔하게 폼 관리하기

눙엉 2024. 2. 13. 22:56

form의 로직을 작성할 때, 페이지 단위에서 컨테이너 단위로 쪼개 개발하다 보면, 가장 최상위에서 위치한 커스텀 훅에 존재하는 React Hook Form의 메서드들을 각 컨테이너의 props로 전달해야 할 때가 있습니다.

 

아래의 예시 코드를 살펴봅시다.

// 여러 폼 로직을 포함한 커스텀 훅
const useCustomFormHook = () => {  
  const { watch, register } = useForm();
  
  return {
    watch,
    register
  }
}

// Name, Age로 이루어진 페이지
const Page = () => {
  const { watch, register } = useCustomFormHook();

  return (
  <form> 
    <Name watch={watch} register={register}/>
    <Age watch={watch} register={register}/>
  </form>
  )
}

const Name = ({watch, register}) => {
  return (
    <div>
      {...}
      <input {...register("name")}/>
    </div>
  )
}

const Age = ({watch, register}) => {
  return (
    <div>
      {...}
      <input {...register("age")}/>
    </div>
  )
}

 

 

위와 같은 코드에서는 컴포넌트의 깊이가 깊어질수록 계속해서 폼 메서드들을 props로 전달해주어야 합니다. 이로 인해 코드가 중복되고 길어지는 문제가 발생합니다.

 

이러한 문제들을 FormProvider와 useFormContext를 사용하여 깊이가 깊더라도 중복 코드를 효과적으로 제거할 수 있습니다. 아래의 예시 코드를 확인해보세요.

 

// 여러 폼 로직을 포함한 커스텀 훅
const useCustomFormHook = () => {  
  const formMethod = useForm();
  
  return {
    formMethod
  }
}

// Name, Age로 이루어진 페이지
const Page = () => {
  const { formMethod } = useCustomFormHook();

  return (
  <FormProvider {...formMethod}>
    <form> 
      <Name />
      <Age />
    </form>
  </FormProvider>
  )
}

const Name = () => {
  const { watch, register } = useFormContext();

  return (
    <div>
      {...}
      <input {...register("name")}/>
    </div>
  )
}

const Age = () => {
  const { watch, register } = useFormContext();
  
  return (
    <div>
      {...}
      <input {...register("age")}/>
    </div>
  )
}

 

FormProvider와 useFormContext를 사용하면 폼 메서드들을 중복으로 props로 전달하지 않아도 되어 중복 코드를 효과적으로 제거할 수 있습니다.

 


기존에는 커스텀 훅 내부에서 폼 관련된 모든 로직을 한 곳으로 통합하여 개발하는 방식을 사용했었습니다. 그러나 폼의 내용이 커질수록 커스텀 훅의 코드 양이 증가하면서 유지보수가 어려워지는 문제가 발생했습니다. 

최근에는 FormProvider와 useFormContext를 활용하여 중복되는 props를 제거하고, 각 컨테이너 또는 컴포넌트에서 필요한 폼 메서드를 직접 가져오는 방식을 채택하고 있습니다. 이로써 해당 컨테이너나 컴포넌트에서만 사용하는 특정 핸들러와 같은 부분은 커스텀 훅에 작성하지 않고, 해당하는 곳에서 직접 작성하여 사용하고 있습니다.

이러한 방식의 장점은 중복되는 props를 줄일 수 있고, 각 컨테이너에서 필요한 폼 메서드를 직접 사용함으로써 코드 양이 줄어들어 유지보수에 용이하다는 점입니다. 그러나 단점으로는 폼 관련 로직이 흩어져 있어 한눈에 이해하기 어려울 수 있다는 점이 있습니다.

현재로서 어떤 방식이 정답인지는 잘 모르겠습니다. 이 글을 읽으시는 분들의 생각을 공유해 주시면 감사하겠습니다 :)