기존 Form 양식에 중복되는 input이 많다 보니 Form 전용 input을 재사용 하기 위해 별도의 컴포넌트로 분리하면 어떨까라는 생각을 했었다.
<input className="..." type="text" name="email" onChange={...} placeholder="이메일" />
<input className="..." type="password" name="password" onChange={...} placeholder="비밀번호" />
// 그 외에 input들...
const emailInput = {
id: 1,
name: 'email',
type: 'text',
placeholder: '이메일',
};
const passwordInput = {
id: 2,
name: 'password',
type: 'password',
placeholder: '비밀번호: 최소 8자리 이상 25자리 이하 (알파벳, 특수문자 포함)',
};
const passwordConfirmInput = {
id: 3,
name: 'passwordConfirm',
type: 'password',
placeholder: '비밀번호 확인',
};
const businessNumberInput = {
id: 4,
name: 'businessNumber',
type: 'text',
placeholder: '사업자등록번호 (11자리)',
minLength: 11,
maxLength: 11,
onKeyDown: onKeyDownHandler,
};
const inputOptions: Record<string, InputType[]> = {
'/auth/login': [emailInput, passwordInput],
'/auth/signup': [emailInput, passwordInput, passwordConfirmInput, businessNumberInput],
'/auth/findPassword': [emailInput],
'/auth/reset': [passwordInput, passwordConfirmInput],
};
const inputs = inputOptions[path];
return (
<>
{inputs.map((input: InputType) => {
const key = input.name as keyof typeof value;
if (input) {
return (
<input
key={input.id}
className={styles['input']}
name={input.name}
value={value[key]}
onChange={onChangeHandler}
type={input.type}
placeholder={input.placeholder}
minLength={input.minLength}
maxLength={input.maxLength}
onKeyDown={input.onKeyDown}
required
/>
);
}
})}
</>
);
각 input 속성으로 들어 갈 내용들을 객체로 정리 하고 path 기준으로 배열로 분리했다. 훨씬 보기 간결하고 이해하기 쉬워졌으나 길어지는 건 마찬가지였다.
하지만, 해당 배열의 각 들어간 요소들을 map으로 출력해주니 input 요소는 한 개만 작성해도 되다 보니 마음이 편해졌다 😀
결론은 Form 컴포넌트 안에는 아래 한 줄만 추가하면 Form이 있는 경로 마다 input이 동적으로 변경된다.
<Input ... />
결국엔 Form도 계속 재사용을 해야 하기 때문에 각각의 불러올 데이터로 세분화 해서 Form으로 데이터로 보내줬다.
import { useRouter } from 'next/router';
import AuthForm from './AuthForm';
type AuthObjectType = Record<string, string>;
const User = () => {
const path = useRouter().pathname;
const LOGIN_DATA = {
url: '/auth/signup',
subUrl: '/auth/findPassword',
title: '편리함의 시작',
subTitle: 'Magic Pos',
subName: '비밀번호를 잊으셨나요?',
caption: '아직 회원이 아니신가요? 회원가입하러 가기',
buttonName: '로그인',
};
const SIGNUP_DATA = {
url: '/auth/login',
title: '편리함의 시작',
subTitle: 'Magic Pos',
caption: '이미 가입을 하셨나요? 로그인하러 가기',
buttonName: '회원가입',
subButtonName: '사업자등록번호 인증',
};
const FIND_PASSWORD_DATA = {
title: '편리함의 시작',
subTitle: 'Magic Pos',
description: '가입하신 이메일을 입력해 주세요.',
buttonName: '링크 전송',
};
const UPDATE_PASSWORD_DATA = {
title: '편리함의 시작',
subTitle: 'Magic Pos',
buttonName: '비밀번호 변경',
description: '새로운 비밀번호를 입력해 주세요.',
};
const AuthData: Record<string, AuthObjectType> = {
'/auth/login': LOGIN_DATA,
'/auth/signup': SIGNUP_DATA,
'/auth/findPassword': FIND_PASSWORD_DATA,
'/auth/reset': UPDATE_PASSWORD_DATA,
};
return <AuthForm data={AuthData[path]} />;
};
export default User;
Form으로 보낼 데이터들 또한, 객체 형태로 만들어서 집합 객체로 감싸주었고 Key를 path로 지정한 다음에 path가 들어오면 AuthData[path]
로 path의 key를 매칭해서 데이터를 보내준 형태로 작성했다.
만약 보여줘야할 Form이 늘어난다면 한 객체씩 추가를 해줘야하는 수고가 들긴 한다..