bkdragon's log

변신하는 Form 본문

concept

변신하는 Form

bkdragon 2023. 10. 18. 23:16

오랜만의 글이다! 최근에 취업에 성공해 바쁘게 살고 정신없이 살다보니 소홀해진 것 같다. 공부는 꾸준하게 하고 있다.

 

오늘은 변신가능한 폼을 만들어서 소개해보려고 한다. 페이지를 사용하다 보면 다양한 형태의 폼을 만날 수 있다. 처음 페이지를 들어가서 거의 바로 회원가입 폼과 로그인 폼을 만날 텐데 이 둘만 하더라도 약간의 형태가 바뀐다. 프론트엔드 개발자로서 이런 것들을 한번에 처리하고 싶은 욕구가 생겨서 만들어보게 되었다!

 

물론! 로그인 폼, 회원가입 폼, 글 작성 폼 등 책임을 세분화하여 하는 것이 좋다. (코드를 이해하는 면에서도 그렇다 내가 짜서 잘 모르겠지만 어쪄면 변신 폼은 약간 어렵고 난해한 코드일 수 있다.)

 

포인트는 다음과 같다.

1. context api  없는 합성 컴포넌트

2. 비제어 컴포넌트

 

포인트를 생각하며 코드를 보자.

 

import React, { PropsWithChildren } from 'react';

import CompoundInput, { CompoundInputProps } from './CompoundInput';

interface CompoundFormProps {
  onSubmit: () => void;
}

const CompoundForm: React.FC<PropsWithChildren<CompoundFormProps>> & {
  Input: React.FC<CompoundInputProps>;
} = ({ children, onSubmit }) => {
  return <form onSubmit={onSubmit}>{children}</form>;
};

CompoundForm.Input = CompoundInput;

export default CompoundForm;

 

폼을 제출하는 함수는 외부로부터 받아오고 있다. 이 폼을 사용하는 컴포넌트에서 사용할 데이터의 형태가 결정되기 때문이다.

Input 컴포넌트의 코드도 확인해보자.

 

import React from 'react';

import { UseFormRegisterReturn, FieldErrors } from 'react-hook-form';

import { ErrorMessage } from '@hookform/error-message';

export interface CompoundInputProps {
  register: UseFormRegisterReturn<string>;
  name: string;
  errors: FieldErrors;
  style?: React.CSSProperties;
}

const CompoundInput: React.FC<CompoundInputProps> = ({
  register,
  errors,
  name,
  style,
}) => {
  return (
    <div>
      <input {...register} style={style} />
      <ErrorMessage
        errors={errors}
        name={name as unknown as any}
        render={({ messages }) =>
          messages &&
          Object.entries(messages).map(([type, message]) => (
            <p key={type} style={{ color: 'red' }}>
              {message}
            </p>
          ))
        }
      />
    </div>
  );
};

export default CompoundInput;

 

 

react hook form 에서 제공하는 register 등을 props로 받아온다. 일일히 상태를 만들지 않고 비제어 컴포넌트 형식으로 폼을 제출하려고 이 방식을 택했다. 검증이 편한건 덤이다.

 

이제 이렇게 작성한 컴포넌트를 아래처럼 사용할 수 있다. 우선은 이메일과 패스워드만 존재하는 폼이 경우이다.

 

const TestForm = () => {
  const {
    register,
    handleSubmit,
    formState: { errors },
  } = useForm<{ email: string; password: string }>();

  const onSubmit = (data: { email: string; password: string }) => {
    console.log(data);
  };

  return (
    <div>
      <CompoundForm onSubmit={handleSubmit(onSubmit)}>
        <CompoundForm.Input
          register={register('email', { required: '입력요망' })}
          name="email"
          errors={errors}
        />
        <CompoundForm.Input
          register={register('password')}
          name="password"
          errors={errors}
        />
      </CompoundForm>
    </div>
  );
};

 

onSubmit 은 완벽하게 구현은 안되어있다. 비동기 코드가 들어가게 될 것이다. 이제 여기서 name 이라는 값이 추가된다면 

 useForm에 타입 수정해주고 Compound.Input 추가해주고 하면 끝이다. 변화하는 폼의 완성이다.

'concept' 카테고리의 다른 글

ws와 was  (0) 2024.10.26
에러 헨들링에 관하여  (0) 2024.06.14
CSS 프레임워크로 atomic design pattern 적용하기  (0) 2023.09.02
[Redux-toolkit] 비동기 처리하기  (0) 2023.09.01
flex-item  (0) 2023.08.30