React Hooks 도입 후 Custom Hook으로 폼 로직 재사용하기

배경

회원가입, 로그인, 설정 페이지 등 폼을 다루는 컴포넌트가 많아지면서 input 상태 관리와 validation 로직이 중복되기 시작했다. 기존에는 HOC로 처리했지만 wrapper hell과 props drilling 문제가 있었다.

React 16.8이 정식 릴리즈된 후 Hooks를 점진적으로 도입 중이었고, Custom Hook으로 이 문제를 해결할 수 있을 것 같았다.

useForm 구현

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 = (onSubmit, validate) => (e) => {
    e.preventDefault();
    const validationErrors = validate ? validate(values) : {};
    setErrors(validationErrors);
    
    if (Object.keys(validationErrors).length === 0) {
      onSubmit(values);
    }
  };

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

사용 예시

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

  const validate = (values) => {
    const errors = {};
    if (!values.email.includes('@')) {
      errors.email = '유효한 이메일을 입력하세요';
    }
    if (values.password.length < 6) {
      errors.password = '비밀번호는 6자 이상이어야 합니다';
    }
    return errors;
  };

  const onSubmit = (values) => {
    console.log('로그인:', values);
  };

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

결과

5개 폼 컴포넌트에 적용했더니 약 200줄의 중복 코드가 제거됐다. HOC 대비 컴포넌트 구조도 훨씬 간결해졌고, 디버깅도 쉬워졌다. Hooks의 조합 가능성 덕분에 다른 Custom Hook과도 쉽게 결합할 수 있었다.

아직 팀 전체가 Hooks에 익숙하지 않아 러닝 커브는 있지만, 점진적으로 확대 적용할 계획이다.

React Hooks 도입 후 Custom Hook으로 폼 로직 재사용하기