[React] React Hook Form에서 다중 값을 하나의 필드로 조합하여 넘겨주기

·2024년 7월 4일
0

React

목록 보기
8/8

다중 페이지 회원가입 폼을 한번에 관리하기 위해 react-hook-form을 이용 중이다.
인풋에 입력한 값은 {...register('name')}와 같이 필드를 연결해서 넘겼다. handleSubmit 함수를 사용하여 폼 제출을 처리할 때, React Hook Form은 등록된 필드의 값들을 모아서 data 객체로 전달해준다. 직접 데이터를 처리할 경우 이런 기능을 사용할 수 없다.

          <Input
            type='text'
            {...register('name')}
            placeholder='이름을 입력해주세요.'
          />

예시로 이렇게 하면 인풋에 입력한 텍스트가 'name' 필드값으로 넘어간다.

  const [joinData, setJoinData] = useState({
    username: '',
    password: '',
    name: '',
    sex: '',
    nickname: '',
    address: '',
    birth: '',
    primaryPositions: '',
  });
...
 const updateData = (data: any) => {
    setJoinData((prevData) => ({ ...prevData, ...data }));
  };

참고로 각 페이지에 updateData 함수를 props로 내려줘서 인풋에 입력된 값들을 업데이트 해주고 있었다.

  • 문제

문제는 생년월일 필드에서 발생했다. birth라는 하나의 필드 값을 넘겨야 하는데, 입력값을 한번에 받는 게 아니라 년/월/일 3개가 필요했다. 인풋 3개에 각 값을 받아와서 '240704' 같은 형태로 조합해 다음과 같이 birth로 넘겨주었다. 값이 다음 페이지로 잘 넘어갔지만, 실제로 최종 폼 제출을 할 때는 birth 값이 들어오고 있지 않다는 것을 확인했다.

  • 기존 코드
import { useFormContext } from 'react-hook-form';

  const {
    register,
    handleSubmit,
    setValue,
  } = useFormContext();

...

const nextHandler = (data: any) => {
    const birth = `${selectedYear}${selectedMonth}${selectedDay}`;
    data.birth = birth;
    updateData(data);
    onNext();
  };

nextHandler 함수에서 data.birth를 직접적으로 설정하고 updateData 함수를 통해 전달하는 방식은 React Hook Form과의 연동을 무시하고 있기 때문에 데이터가 정상적으로 넘어가지 않은 것이었다.

  • 문제 해결

다중 값을 하나의 필드 값으로 넘겨주고 싶다면, setValue를 사용하여 React Hook Form에 값을 설정할 수 있다.

  • 수정한 코드
  const nextHandler = handleSubmit((data: any) => {
    const birth = `${selectedYear}${selectedMonth}${selectedDay}`;
    setValue('birth', birth);
    updateData(data);
    onNext();
  });

이렇게하니 최종 제출시 birth 값이 잘 들어온다!

그러나
이게 끝이 아니다.
필드 값을 수정할 때마다 업데이트 해주어야 하기 때문!

  useEffect(() => {
    if (selectedYear && selectedMonth && selectedDay) {
      const birth = `${selectedYear}${selectedMonth}${selectedDay}`;
      setValue('birth', birth);
    }
  }, [selectedYear, selectedMonth, selectedDay, setValue]);

...

  const nextHandler = (data: any) => {
    updateData(data);
    onNext();
  };

useEffect를 사용해 각 필드의 상태(selectedYear, selectedMonth, selectedDay)가 변경될 때마다 setValue를 통해 React Hook Form의 필드 값을 업데이트해주었다. 이러한 방식으로 React Hook Form의 관리를 유지하면서도 복잡한 상태 관리를 간소화할 수 있다. 게다가 nextHandler와도 분리해서 더욱 깔끔한 코드가 되었다.
react-hook-form을 좀 더 이해하게 되었던 시간이다.

  • 덧붙여! useFormContext의 활용

useFormContext는 React Hook Form 라이브러리에서 제공하는 훅으로, FormContext를 통해 하위 컴포넌트에서 폼 상태와 메서드에 접근할 수 있게 해준다.
처음에는 각 인풋의 값을 일일히 제어하고 있었는데, useFormContext의 watchsetValue를 활용하면서 코드가 깔끔해졌다.
setValue: 폼 필드의 값을 설정할 수 있게 해주는 메서드. 특정 필드의 값을 업데이트해야 할 때 사용한다.
watch: 폼 필드의 값을 관찰하고 값이 변경될 때마다 업데이트된 값을 반환하는 메서드. 폼 필드의 현재 상태를 실시간으로 추적할 수 있다.

  • 예시
  const { register, handleSubmit, setValue, watch } = useFormContext();

...

  const username = watch('username') as string;

...

  const nextHandler = (data: any) => {
    updateData(data);
    onNext();
  };

...
          <Input
            type='email'
            {...register('username')}
            name='username'
            value={username}
            onChange={(e) => setValue('username', e.target.value)}
            placeholder='이메일을 입력해주세요.'
          />
        <NextButton
          type='submit'
          onClick={handleSubmit(nextHandler)}
        >
          다음
        </NextButton>

이렇게 하면 인풋에 입력된 'username' 값이 실시간으로 추적되고, 'username'라는 필드 값으로 넘어가서 제출까지 완료!

profile
주니어 프론트엔드 웹 개발자 🐛

0개의 댓글