InputField.tsx
컴포넌트는 label
, input
, button
을 함께 렌더링하는 구조인데, 특정 상황에서는 버튼이 필요 없는 경우도 있어 조건에 따라 버튼 렌더링을 제어해야 했습니다.
// 버튼이 필요한 경우 InputField 사용 예시
<InputField
// InputField의 기본 props
id="id"
label="아이디"
placeholder="아이디를 입력해 주세요"
onChange={handleChange}
message={validationStatus.message}
isValid={validationStatus.isValid}
// 버튼 관련 props
isPending={isPending} // 버튼 로딩 상태
buttonText="중복확인" // 버튼에 표시할 텍스트
buttonEnabled={validationStatus.isValid} // 버튼 활성화 여부
onClick={() => mutate()} // 버튼 클릭 시 실행할 함수
/>
그런데 버튼을 렌더링해야 할 경우 넘겨야 하는 props가 많아지면서, 구조가 점점 복잡해졌습니다.
버튼이 필요한 경우 넘겨야 할 props가 점점 많아지면서, InputField
컴포넌트가 본래의 역할 이상으로 많은 책임을 지게 되었습니다.
그래서 고민 끝에, 버튼 관련 props를 모두 개별로 넘기는 대신, 버튼 컴포넌트 자체를 props로 전달하는 방식으로 구조를 개선해보기로 했습니다.
// 버튼 관련 props를 InputField에 직접 넘기지 않고,
// 버튼 컴포넌트를 분리해 actionButton props로 전달한 경우
<InputField
// InputField의 기본 props
...
// 버튼 컴포넌트를 직접 전달
actionButton={
<LoadingSpinnerButton
isPending={isPending} // 버튼 로딩 상태
buttonText="중복확인" // 버튼에 표시할 텍스트
buttonEnabled={validationStatus.isValid} // 버튼 활성화 조건
onClick={() => mutate()} // 클릭 시 실행할 함수
/>
}
/>
// InputField.tsx 내부 (컴포넌트 정의)
interface InputFieldProps extends React.InputHTMLAttributes<HTMLInputElement> {
// ...기타 input 관련 props
actionButton?: React.ReactNode; // 버튼 컴포넌트 직접 전달
}
export default function InputField({
...,
actionButton,
...props
}: InputFieldProps) {
return (
<div className="...">
<label htmlFor={id}>{label}</label>
<div className="flex gap-2">
<Input id={id} {...props} />
{actionButton && <div>{actionButton}</div>}
</div>
</div>
);
}
이처럼 버튼을 직접 넘기는 방식으로 구조를 변경하면서, InputField
는 본래의 역할인 입력 필드 렌더링에만 집중할 수 있게 되었고, 버튼 로직은 별도 컴포넌트에서 자유롭게 관리할 수 있게 되었습니다.
버튼 컴포넌트를 직접 넘기는 방식으로 구조를 개선하면서 다음과 같은 이점을 얻을 수 있었습니다.
복잡했던 props 구조를 단순화하고, 컴포넌트 간 책임도 더 명확하게 나눌 수 있었습니다.
끝내주는 기능 더 만들어주세요