프로필

프로필 사진
Popomon
Frontend Developer
(2020/12 ~)

    카테고리

    포스트

    [Frontend/useForm] 리액트 훅을 이용한 form 태그 다루기

    2021. 1. 27. 12:12

    꿈가게: To Do List - iOS

    꿈가게: To Do List - Android

    리액트에서 form 태그와 input 태그를 이용하여 데이터를 등록 및 수정하는 경우에는 상당히 많은 양의 코드가 필요합니다. 우선 onChange 함수를 이용하여 각각의 input 태그의 value 값에 useState 훅을 이용하여 상태값과 연결해야 합니다. 이어서 각각의 input 태그의 값 마다 값이 타당한지를 알아보기 위한 밸리데이션 체크를 해야합니다.

     

    이러한 작업이 form 태그 마다 한번씩 필요한 작업입니다. 따라서 이러한 상태값을 연결하거나 밸리데이션 체크를 하는 코드를 리액트 훅으로 정의하여 좀 더 편하게 form 태그를 사용할 수 있도록 작성해 보도록 하겠습니다.

     


    상태값 관리하기

    form 태그의 상태값은 values 라는 변수를 통해서 관리하고, error 메시지는 errors 라는 변수를 통해서 관리합니다. 다음 코드에서 확인하실 수 있습니다.

     

    const [values, setValues] = useState<any>({});
    const [errors, setErrors] = useState<any>({});

     

    위에서 정의한 변수와 에러 메시지는 input 태그에서 다음과 같이 활용될 수 있습니다.

     

    <input onChange={handleChange} name="id" value={values.id} />
    {errors.id && <p>{errors.id}</p>}
    

     


    이벤트 정의하기

    form 태그의 onSubmit 함수와 form 태그 안에 있는 input 태그의 onChange 함수를 다음과 같이 정의할 수 있습니다.

     

    const handleChange = (
      e: React.ChangeEvent<HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement> | any
    ) => {
      const { name, value } = e.target;
      setValues({
        ...values,
        [name]: value,
      });
    };
    
    const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
      e.preventDefault();
      setErrors(validate(values));
    };

     

    위에서 정의한 handleSubmit 함수와 handleChange 함수는 리액트 컴포넌트에서 다음과 같이 사용될 수 있습니다.

     

    <form onSubmit={handleSubmit}>
      <input onChange={handleChange} name="id" value={values.id} />
      {errors.id && <p>{errors.id}</p>}
    </form>

     


    초기화 함수 정의하기

    리액트 컴포넌트는 처음 마운트가 될 때, 모든 상태값들을 초기화를 해주어야 합니다. 그렇지 않으면, null 이나 undefined 값이 컴포넌트에 들어갈 수 있기 때문입니다. 뭔가 의도적으로 그 값을 넣어야 하는 경우가 아니라면 초기화를 해주는 것이 좋습니다.

     

    따라서 다음과 같은 초기화 함수를 추가로 작성합니다.

     

    const setDefaultValue = function(values: any){
      setValues(values);
    }

     

    이제 모든 작업이 끝났습니다. 완성된 리액트 훅을 보도록 하겠습니다.

     


    리액트 훅 - useForm

    import { useState } from "react";
    
    const useForm = (validate: (v: any) => {}) => {
      const [values, setValues] = useState<any>({});
      const [errors, setErrors] = useState<any>({});
    
      const handleChange = (
        e: React.ChangeEvent<HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement> | any
      ) => {
        const { name, value } = e.target;
        setValues({
          ...values,
          [name]: value,
        });
      };
    
      const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
        e.preventDefault();
        setErrors(validate(values));
        console.log("values", values);
        console.log("errors", errors);
      };
    
      const setDefaultValue = function(values: any){
        setValues(values);
      }
    
      return { handleChange, values, handleSubmit, errors, setDefaultValue };
    };
    
    export default useForm;
    

     

    그런데 이 훅을 활용하기 위해서는 밸리데이션 함수를 별도로 정의해야할 필요가 있습니다!

    우선 빠르게 밸리데이션 함수를 정의해 보자면 아래와 같습니다.

     

    errors 오브젝트를 선언한 다음, 인자로 전달받은 values 안에있는 속성을 하나씩 검사해서 값이 올바르지 않다면, 에러 메시지를 넣어주는 것입니다. 이렇게 잘못된 값에 대해서만 에러메시지를 넣은 다음 리턴해줍니다.

     

    export function validateXXXForm(values: any) {
      let errors: any = {};
    
      if (!values.name) {
        errors.name = "Name required";
      }
    
      return errors;
    }

     

    이제 리액트 컴포넌트에서는 컴포넌트에 맞는 밸리데이션 함수를 사용하여 useForm 훅을 사용하실 수 있습니다. 아래 코드를 보시면 useForm 훅을 사용하여 컴포넌트가 마운트 되는 타이밍에 상태값을 초기화 해 준 것을 확인할 수 있습니다.

     

    // useForm 훅을 호출
    const {
      setDefaultValue,
      values,
      errors,
      handleChange,
      handleSubmit,
    } = useForm(validateXXXForm);
    
    // 상태값 초기화
    useEffect(() => {
      setDefaultValue({
        name: "",
      });
    }, []);

     

    이제 컴포넌트에 그대로 연결하여 에러 및 상태값을 사용할 수 있습니다.

     

    interface Props {}
    
    export default function SessionEdit({}: Props): ReactElement {
      // useForm 훅을 호출
      const {
        setDefaultValue,
        values,
        errors,
        handleChange,
        handleSubmit,
      } = useForm(validateXXXForm);
    
      // 상태값 초기화
      useEffect(() => {
        setDefaultValue({
          name: "",
        });
      }, []);
    
      return (
        <form onSubmit={handleSubmit}>
          <input onChange={handleChange} name="id" value={values.id} />
          {errors.id && <p>{errors.id}</p>}
        </form>
      );
    }