React Hooks 도입 후 Custom Hook으로 폼 로직 정리하기

배경

회원가입, 로그인, 프로필 수정 등 폼을 다루는 컴포넌트가 늘어나면서 비슷한 상태 관리 코드가 반복되고 있었다. React 16.8에서 Hooks가 정식 출시된 후 몇 달간 관망하다가, 이번 스프린트에서 본격적으로 적용해보기로 했다.

useForm 구현

가장 기본적인 폼 로직을 Custom Hook으로 분리했다.

import { useState } from 'react';

function useForm(initialValues) {
  const [values, setValues] = useState(initialValues);
  const [errors, setErrors] = useState({});

  const handleChange = (e) => {
    const { name, value } = e.target;
    setValues(prev => ({
      ...prev,
      [name]: value
    }));
  };

  const handleSubmit = (callback) => (e) => {
    e.preventDefault();
    callback(values);
  };

  return {
    values,
    errors,
    setErrors,
    handleChange,
    handleSubmit
  };
}

사용 예시

로그인 폼에서 이렇게 사용할 수 있다.

function LoginForm() {
  const { values, handleChange, handleSubmit } = useForm({
    email: '',
    password: ''
  });

  const onSubmit = async (data) => {
    try {
      await api.login(data);
    } catch (error) {
      console.error(error);
    }
  };

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <input
        name="email"
        value={values.email}
        onChange={handleChange}
      />
      <input
        name="password"
        type="password"
        value={values.password}
        onChange={handleChange}
      />
      <button type="submit">로그인</button>
    </form>
  );
}

결과

Class 컴포넌트로 작성했던 기존 폼들을 모두 Hooks로 전환했다. 컴포넌트당 평균 50줄 정도 코드가 줄었고, 테스트 작성도 더 간단해졌다. 다만 팀원들이 적응하는데 1~2주 정도 시간이 필요했다.

다음 단계로는 validation 로직도 Hook에 통합할 예정이다.

React Hooks 도입 후 Custom Hook으로 폼 로직 정리하기