Input 공통 컴포넌트 #81
sgoldenbird
started this conversation in
Engineering Breakdown
Replies: 0 comments
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
1. ✨ 설계 배경 및 목적
Input 컴포넌트는 합성 컴포넌트(Compound Component) 패턴을 기반으로 설계되었습니다. 이 디자인의 주요 목적은 다음과 같습니다.
재사용성 및 일관성:
다양한 입력 필드(text, password, textarea, file, number 등)에 대해 일관된 마크업과 스타일을 제공하여,
개별 필드를 매번 새로 작성할 필요 없이 통일된 UI/UX를 유지할 수 있도록 합니다.
유연한 조합:
Label, Field, Helper 등 각 부분을 독립적인 컴포넌트로 분리하여,
개발자가 필요한 요소만 선택적으로 조합하거나 순서를 변경하는 등 유연하게 UI를 구성할 수 있습니다.
상태 관리 분리:
react-hook-form과 긴밀하게 통합되어, 입력 필드 자체는 순수한 UI 역할에 집중하고
폼 데이터 관리, 유효성 검사, 에러 상태 처리 등의 복잡한 로직은 Input.Root 컴포넌트와 react-hook-form에 위임합니다.
2. 🧱 구성요소 및 구조
Input 컴포넌트는 src/shared/components/ui/input 디렉토리 아래에 다음과 같은 파일 구조로 구성되어 있습니다.
3. ⚙️ 동작 흐름 요약
4. 🔮 설계 의도 및 고려사항
Compound Component 패턴:
Input.Root가 모든 상태를 중앙에서 관리하고, 하위 컴포넌트들이 InputContext를 통해 필요한 상태와 함수에 접근합니다.
이로써 Input 컴포넌트 사용 시 코드가 더 직관적이고 재사용 가능해집니다.
통합된 상태 관리:
react-hook-form의 control 객체를 활용하여 입력값, 유효성, 에러 상태를 효과적으로 관리하고,
useWatch를 통해 실시간으로 파일명이나 글자 수를 추적합니다.
접근성(Accessibility):
Input.Label은 id와 htmlFor 속성으로 필드와 자동으로 연결되며,
Input.Trigger는 aria-label과 role 속성을 통해 스크린 리더를 지원하도록 설계되었습니다.
재사용 가능한 유틸리티:
cn 유틸리티 함수를 사용하여 Tailwind CSS 클래스를 조건부로 적용하고 병합함으로써, 복잡한 스타일링 로직을 간결하게 유지합니다.
5. 🪄 세부 설명: 주요 훅 / 컴포넌트 / 유틸
모든 Input 컴포넌트의 부모 역할을 하며, id 생성, react-hook-form의 register, errors, control을 통해 입력 상태를 가져와 InputContext를 통해 하위 컴포넌트에 제공합니다.
text, password, textarea 등 다양한 타입의 요소를 렌더링하는 핵심 컴포넌트입니다. InputContext로부터 register를 받아 필드에 적용하므로 별도의 onChange나 value 처리가 필요 없습니다.
react-hook-form의 errors 객체에 기반한 에러 메시지를 표시하거나, maxLength가 있는 textarea의 경우 현재 글자 수를 표시하는 등 사용자에게 유용한 정보를 제공합니다.
type이 password인 경우 비밀번호를 보이거나 숨기는 password-toggle 버튼을, type이 file인 경우 파일 선택을 위한 file-upload 버튼을 렌더링합니다.
컴포넌트의 다양한 사용 예시를 담고 있으며, src/app/test/input/page.dev.tsx 경로와 Storybook에서 실제로 동작하는 모습을 확인할 수 있습니다.
6. 🧩 사용 예시 및 패턴
Input 컴포넌트는 react-hook-form의 FormProvider와 함께 사용됩니다.
기본 텍스트 입력
비밀번호 입력(토글 버튼 포함)
파일업로드(미리보기 포함)
7.⚠️ 사용 시 주의사항
Input 컴포넌트는 react-hook-form의 useFormContext를 사용하므로, 반드시 부모 컴포넌트에서 FormProvider로 감싸줘야 합니다.
Input 컴포넌트의 모든 하위 요소는 반드시 Input.Root 컴포넌트 내부에 위치해야 합니다.
Input.Root에는 react-hook-form 필드와 연결하기 위한 name 속성이 반드시 필요합니다.
향후 개선을 위해 다음과 같은 접근을 고려해볼 생각입니다.
Input.Root의 확장: Input.Root 컴포넌트가 multiple prop을 지원하도록 확장하고, useWatch에서 value를 FileList 그대로 받을 수 있도록 수정합니다. 이를 통해 InputContext가 여러 파일의 상태를 관리하고, Input.Trigger에서 여러 이미지 미리보기를 렌더링할 수 있도록 로직을 추가할 수 있습니다.
react-hook-form의 Controller 활용: 복잡한 입력 필드의 경우 Controller를 사용하여 onChange와 value를 직접 제어하는 것이 더 안전하고 유연합니다. IntroImageInput처럼 Input.Root를 Controller의 render prop 내부에 배치하여, 폼의 상태와 UI 로직을 분리하는 전략을 유지할 수 있습니다.
useFieldArray 훅 활용: 여러 파일을 추가/제거하는 기능을 구현할 때, react-hook-form의 useFieldArray 훅을 사용하면 각 파일을 개별적인 폼 필드로 취급하여 관리하기 용이합니다. 이 방법을 사용하면 파일마다 별도의 유효성 검사 규칙을 적용하거나 순서를 바꾸는 등 더 복잡한 로직을 구현할 수 있습니다.
8. 📎 참고 파일 및 링크
Beta Was this translation helpful? Give feedback.
All reactions