Q4. 공통 Input/Fieldset 컴포넌트 — 합성을 위해 만드는 게 맞을까?
크루의 질문
“공통 fieldset 컴포넌트를 사용하여 카드번호, 유효기간, cvc의 컴포넌트를 만들었습니다. payment에서 이 컴포넌트들을 합성하여 사용하였고, value 상태랑 유효성 검사 값이 payment에 있는데, 공통 fieldset 컴포넌트가 필요한지 궁금합니다.” — 콘티·먼지 페어
“컴포넌트 쪼개는 기준에 대해 얘기를 많이 했습니다.” — 파라디·피트·이현 페어
AS-IS 코드
🔍 읽기 전에
이 Input 컴포넌트의 책임을 한 문장으로 적어보면 어떨까요?
그 한 문장에 몇 가지 일이 들어 있나요?
// src/components/@common/Input/Input.tsx
Input.Label = Label;
Input.Limit = Limit;
export default Input;
interface InputItemsContext {
itemMap: Map<string, { ref: RefObject<HTMLInputElement | null> }>;
}
const InputItemsContext = createContext<InputItemsContext>({
itemMap: new Map(),
});
const useInputItemsContext = () => useContext(InputItemsContext);
function InputItemsProvider({ children }: PropsWithChildren) {
const itemMap = useRef<InputItemsContext['itemMap']>(new Map()).current;
return <InputItemsContext.Provider value={{ itemMap }}>{children}</InputItemsContext.Provider>;
}
function InputItem({ children }: PropsWithChildren) {
const { itemMap } = useInputItemsContext();
const childrenArray = Children.toArray(children);공식문서 단서 — children으로 합성하기
React 공식문서 Passing JSX as children (한글 번역)이 합성의 기초를 보여준다:
When you nest content inside a JSX tag, the parent component will receive that content in a prop called
children.
페이먼츠에서 fieldset은 *시각적 묶음(레이블 + 입력 영역)*이라는 구조 역할만 가질 수 있다. 그 안에 들어가는 input의 종류·검증·자동 이동이 다르다면, 합성의 단위는 fieldset이 아니라 각 도메인 영역일 수 있다 — children은 부모가 자식의 종류를 알 필요가 없을 때 가장 강하다.
추가로 Reusing Logic with Custom Hooks (요약)의 “같은 코드가 여러 곳에서 반복되면 Custom Hook으로 추출할 수 있다” 는 기준과 짝지어 볼 수 있다. Q1에서 본 AHA 원칙(먼저 1단계 스타일로 완성한 뒤 중복을 본 뒤 추출)을 컴포넌트 추출에도 적용하면, 공통 컴포넌트는 중복과 변화 방향을 본 뒤 만든다는 쪽이 더 안전하다.
선배 PR 읽기 가이드
선배 PR 읽기 가이드 — 펼쳐보기
추가 읽을거리 — Kent C. Dodds · Dan Abramov
외부 글 모음 — 펼쳐보기
Kent C. Dodds — AHA Programming
- 원문: kentcdodds.com/blog/aha-programming
- 한 줄 요약: Avoid Hasty Abstractions — 성급한 추상화를 피하라. 공통 컴포넌트의 prop 인터페이스가 자꾸 넓어진다면 추상화 시점이 너무 빨랐을 가능성. 페이먼츠 2단계 *“먼저 1단계 스타일로 완성한 뒤 추출”*과 이어진다.
Kent C. Dodds — When to break up a component into multiple components
- 원문: kentcdodds.com/blog/when-to-break-up-a-component-into-multiple-components
- 한 줄 요약: 컴포넌트는 언제 쪼개야 하는가. 길이·재사용·복잡성 중 무엇이 진짜 신호인지. 콘티·먼지 페어의 “공통 fieldset 필요한가” 질문을 판단할 때 참고할 기준이 된다.
Dan Abramov — Writing Resilient Components
- 원문: overreacted.io/writing-resilient-components
- 한 줄 요약: 합성된 자식 컴포넌트가 부모 prop 변경에 잘 견디려면 어떤 원칙을 따라야 하는가. 공통 컴포넌트의 *“확장성을 위해 prop을 늘리는 것”*이 어디서부터 비용으로 보이는지의 단서.
연관 PR 더 보기
이 주제에 매핑된 1단계 PR 전체 — 펼쳐보기
자기 가설에 가까운 PR을 골라 추가로 비교해보세요.
| PR | 작성자 | 핵심 키워드 |
|---|---|---|
| #3 | @jho2301 | 객체/배열 state 구조 / 카드번호 4분할 / 공통 Input/컴포넌트 합성 / 검증·에러 처리 / 카드사/브랜드 판별 |
| #4 | @SunYoungKwon | 객체/배열 state 구조 / 카드번호 4분할 / 공통 Input/컴포넌트 합성 / 검증·에러 처리 / 카드사/브랜드 판별 |
| #6 | @Puterism | state 위치 / 공통 Input/컴포넌트 합성 / 카드사/브랜드 판별 |
| #7 | @dudtjr913 | state 위치 / 객체/배열 state 구조 / 공통 Input/컴포넌트 합성 |
| #8 | @goni-ssi | 객체/배열 state 구조 / 카드번호 4분할 / 공통 Input/컴포넌트 합성 |
| #10 | @bucketHaneul | 객체/배열 state 구조 / 공통 Input/컴포넌트 합성 / 검증·에러 처리 |
| #15 | @365kim | 객체/배열 state 구조 / 공통 Input/컴포넌트 합성 / 카드사/브랜드 판별 |
| #16 | @shinsehantan | 객체/배열 state 구조 / 공통 Input/컴포넌트 합성 / 카드사/브랜드 판별 |
| #17 | @zigsong | 객체/배열 state 구조 / 카드번호 4분할 / 공통 Input/컴포넌트 합성 / 카드사/브랜드 판별 |
| #18 | @0imbean0 | 카드번호 4분할 / 공통 Input/컴포넌트 합성 / 검증·에러 처리 / 카드사/브랜드 판별 |
| #19 | @iborymagic | 공통 Input/컴포넌트 합성 / 검증·에러 처리 / 카드사/브랜드 판별 |
| #20 | @hchayan | 객체/배열 state 구조 / 공통 Input/컴포넌트 합성 |
| #22 | @ddongule | 객체/배열 state 구조 / 카드번호 4분할 / 공통 Input/컴포넌트 합성 |
| #25 | @2SOOY | 공통 Input/컴포넌트 합성 / 카드사/브랜드 판별 |
| #28 | @jum0 | 공통 Input/컴포넌트 합성 / 카드사/브랜드 판별 |
| #29 | @swon3210 | state 위치 / 카드번호 4분할 / 공통 Input/컴포넌트 합성 / 카드사/브랜드 판별 |
| #69 | @juunzzi | state 위치 / 공통 Input/컴포넌트 합성 |
| #71 | @DomMorello | state 위치 / 객체/배열 state 구조 / 카드번호 4분할 / 공통 Input/컴포넌트 합성 / 검증·에러 처리 |
| #77 | @JUDONGHYEOK | state 위치 / 객체/배열 state 구조 / 카드번호 4분할 / 공통 Input/컴포넌트 합성 |
| #78 | @soyi47 | state 위치 / 객체/배열 state 구조 / 카드번호 4분할 / 공통 Input/컴포넌트 합성 |
| #81 | @usageness | 공통 Input/컴포넌트 합성 / 카드사/브랜드 판별 |
| #86 | @yunjin-kim | 공통 Input/컴포넌트 합성 |
| #87 | @airman5573 | 공통 Input/컴포넌트 합성 |
| #90 | @prefer2 | 카드번호 4분할 / 공통 Input/컴포넌트 합성 |
| #91 | @moonheekim0118 | custom hook / 카드번호 4분할 / 공통 Input/컴포넌트 합성 / 검증·에러 처리 |
| #93 | @kwannee | 객체/배열 state 구조 / 공통 Input/컴포넌트 합성 / 카드사/브랜드 판별 |
| #94 | @euijinkk | state 위치 / 객체/배열 state 구조 / 카드번호 4분할 / 공통 Input/컴포넌트 합성 / 검증·에러 처리 / 카드사/브랜드 판별 |
| #95 | @KangYunHo1221 | state 위치 / 카드번호 4분할 / 공통 Input/컴포넌트 합성 |
| #97 | @kamwoo | state 위치 / 카드번호 4분할 / 공통 Input/컴포넌트 합성 / 검증·에러 처리 |
| #98 | @byhhh2 | state 위치 / 객체/배열 state 구조 / 공통 Input/컴포넌트 합성 / 카드사/브랜드 판별 |
| #100 | @woose28 | state 위치 / 카드번호 4분할 / 공통 Input/컴포넌트 합성 / 검증·에러 처리 |
| #103 | @kkojae91 | 객체/배열 state 구조 / 카드번호 4분할 / 공통 Input/컴포넌트 합성 |
| #106 | @jin7969 | 객체/배열 state 구조 / 카드번호 4분할 / 공통 Input/컴포넌트 합성 / 검증·에러 처리 |
| #186 | @bassyu | 공통 Input/컴포넌트 합성 / 카드사/브랜드 판별 |
| #187 | @gabrielyoon7 | 객체/배열 state 구조 / 카드번호 4분할 / 공통 Input/컴포넌트 합성 |
| #188 | @ksone02 | 공통 Input/컴포넌트 합성 |
| #191 | @kyw0716 (대표) | 객체/배열 state 구조 / 카드번호 4분할 / 공통 Input/컴포넌트 합성 |
| #194 | @shackstack | 카드번호 4분할 / 공통 Input/컴포넌트 합성 / 검증·에러 처리 |
| #197 | @xodms0309 | state 위치 / 카드번호 4분할 / 공통 Input/컴포넌트 합성 |
| #198 | @ashleysyheo | state 위치 / 객체/배열 state 구조 / 공통 Input/컴포넌트 합성 / 검증·에러 처리 |
| #200 | @hae-on | 객체/배열 state 구조 / 카드번호 4분할 / 공통 Input/컴포넌트 합성 / 검증·에러 처리 |
| #201 | @HyeryongChoi | state 위치 / 객체/배열 state 구조 / 카드번호 4분할 / 공통 Input/컴포넌트 합성 |
| #203 | @nangkyeonglim | state 위치 / 객체/배열 state 구조 / 공통 Input/컴포넌트 합성 |
| #204 | @NaveOWO | state 위치 / 객체/배열 state 구조 / 공통 Input/컴포넌트 합성 |
| #205 | @2yunseong | state 위치 / 객체/배열 state 구조 / 카드번호 4분할 / 공통 Input/컴포넌트 합성 |
| #207 | @inyeong-kang | custom hook / 객체/배열 state 구조 / 공통 Input/컴포넌트 합성 / 검증·에러 처리 |
| #208 | @D0Dam | state 위치 / 객체/배열 state 구조 / 공통 Input/컴포넌트 합성 |
| #209 | @jiwonh423 | state 위치 / 공통 Input/컴포넌트 합성 |
| #210 | @chsua | 카드번호 4분할 / 공통 Input/컴포넌트 합성 |
| #213 | @wzrabbit | state 위치 / 객체/배열 state 구조 / 카드번호 4분할 / 공통 Input/컴포넌트 합성 / 검증·에러 처리 |
| #214 | @n0eyes (대표) | custom hook / 객체/배열 state 구조 / 공통 Input/컴포넌트 합성 / 검증·에러 처리 |
| #215 | @Dahyeeee | state 위치 / 객체/배열 state 구조 / 공통 Input/컴포넌트 합성 |
| #217 | @WaiNaat | 공통 Input/컴포넌트 합성 |
| #218 | @tkdrb12 | 객체/배열 state 구조 / 카드번호 4분할 / 공통 Input/컴포넌트 합성 / 검증·에러 처리 / 카드사/브랜드 판별 |
| #219 | @Creative-Lee | 공통 Input/컴포넌트 합성 |
| #225 | @woo-jk | state 위치 / 공통 Input/컴포넌트 합성 / 검증·에러 처리 |
| #226 | @regularPark | state 위치 / 객체/배열 state 구조 / 공통 Input/컴포넌트 합성 |
| #227 | @jeongwusi | 객체/배열 state 구조 / 카드번호 4분할 / 공통 Input/컴포넌트 합성 |
| #229 | @feb-dain | 객체/배열 state 구조 / 공통 Input/컴포넌트 합성 |
| #230 | @gyeongza | state 위치 / 객체/배열 state 구조 / 카드번호 4분할 / 공통 Input/컴포넌트 합성 |
| #232 | @Gilpop8663 | custom hook / 객체/배열 state 구조 / 카드번호 4분할 / 공통 Input/컴포넌트 합성 / 검증·에러 처리 |
| #233 | @sh981013s | state 위치 / 객체/배열 state 구조 / 공통 Input/컴포넌트 합성 |
| #234 | @yogjin | state 위치 / 객체/배열 state 구조 / 공통 Input/컴포넌트 합성 |
| #331 | @anttiey | state 위치 / 공통 Input/컴포넌트 합성 / 검증·에러 처리 / 카드사/브랜드 판별 |
| #332 | @seongjinme | 카드번호 4분할 / 공통 Input/컴포넌트 합성 / 검증·에러 처리 / 카드사/브랜드 판별 |
| #333 | @jinyoung234 | 객체/배열 state 구조 / 카드번호 4분할 / 공통 Input/컴포넌트 합성 / 검증·에러 처리 / 카드사/브랜드 판별 |
| #334 | @vi-wolhwa | state 위치 / 객체/배열 state 구조 / 카드번호 4분할 / 공통 Input/컴포넌트 합성 / 검증·에러 처리 / 카드사/브랜드 판별 |
| #335 | @healim01 | 객체/배열 state 구조 / 공통 Input/컴포넌트 합성 / 카드사/브랜드 판별 |
| #336 | @jaeml06 | 객체/배열 state 구조 / 카드번호 4분할 / 공통 Input/컴포넌트 합성 / 검증·에러 처리 / 카드사/브랜드 판별 |
| #337 | @jinhokim98 | custom hook / 객체/배열 state 구조 / 카드번호 4분할 / 공통 Input/컴포넌트 합성 / 검증·에러 처리 / 카드사/브랜드 판별 |
| #338 | @Largopie | custom hook / 객체/배열 state 구조 / 카드번호 4분할 / 공통 Input/컴포넌트 합성 / 검증·에러 처리 / 카드사/브랜드 판별 |
| #339 | @Yoonkyoungme | state 위치 / 공통 Input/컴포넌트 합성 / 검증·에러 처리 |
| #340 | @chosim-dvlpr | 객체/배열 state 구조 / 카드번호 4분할 / 공통 Input/컴포넌트 합성 / 검증·에러 처리 / 카드사/브랜드 판별 |
| #341 | @simorimi | state 위치 / 객체/배열 state 구조 / 카드번호 4분할 / 공통 Input/컴포넌트 합성 / 검증·에러 처리 / 카드사/브랜드 판별 |
| #343 | @brgndyy | custom hook / 객체/배열 state 구조 / 카드번호 4분할 / 공통 Input/컴포넌트 합성 / 검증·에러 처리 / 카드사/브랜드 판별 |
| #348 | @pp449 | state 위치 / 객체/배열 state 구조 / 카드번호 4분할 / 공통 Input/컴포넌트 합성 / 검증·에러 처리 / 카드사/브랜드 판별 |
| #349 | @BadaHertz52 | state 위치 / 객체/배열 state 구조 / 카드번호 4분할 / 공통 Input/컴포넌트 합성 / 검증·에러 처리 |
| #353 | @ooherin | custom hook / 객체/배열 state 구조 / 카드번호 4분할 / 공통 Input/컴포넌트 합성 / 검증·에러 처리 |
| #354 | @hwinkr | state 위치 / 객체/배열 state 구조 / 공통 Input/컴포넌트 합성 / 검증·에러 처리 / 카드사/브랜드 판별 |
| #355 | @greetings1012 | 객체/배열 state 구조 / 카드번호 4분할 / 공통 Input/컴포넌트 합성 / 검증·에러 처리 / 카드사/브랜드 판별 |
| #357 | @00kang | state 위치 / 객체/배열 state 구조 / 카드번호 4분할 / 공통 Input/컴포넌트 합성 / 검증·에러 처리 / 카드사/브랜드 판별 |
| #359 | @rbgksqkr | custom hook / 카드번호 4분할 / 공통 Input/컴포넌트 합성 / 검증·에러 처리 / 카드사/브랜드 판별 |
| #360 | @llqqssttyy | 객체/배열 state 구조 / 카드번호 4분할 / 공통 Input/컴포넌트 합성 / 검증·에러 처리 / 카드사/브랜드 판별 |
| #361 | @skiende74 | custom hook / 객체/배열 state 구조 / 공통 Input/컴포넌트 합성 / 검증·에러 처리 / 카드사/브랜드 판별 |
| #362 | @Jaymyong66 | 객체/배열 state 구조 / 카드번호 4분할 / 공통 Input/컴포넌트 합성 / 검증·에러 처리 / 카드사/브랜드 판별 |
| #363 | @chysis | state 위치 / 공통 Input/컴포넌트 합성 / 카드사/브랜드 판별 |
| #413 | @Beomtae | custom hook / 카드번호 4분할 / 공통 Input/컴포넌트 합성 / 검증·에러 처리 |
| #414 | @ohgus | custom hook / 객체/배열 state 구조 / 카드번호 4분할 / 공통 Input/컴포넌트 합성 / 검증·에러 처리 |
| #415 | @eunoia-jaxson | 객체/배열 state 구조 / 카드번호 4분할 / 공통 Input/컴포넌트 합성 / 검증·에러 처리 |
| #416 | @jeongyou | state 위치 / 객체/배열 state 구조 / 카드번호 4분할 / 공통 Input/컴포넌트 합성 / 검증·에러 처리 |
| #417 | @sooyeoniya | custom hook / 카드번호 4분할 / 공통 Input/컴포넌트 합성 / 검증·에러 처리 / 카드사/브랜드 판별 |
| #420 | @ShinjungOh | state 위치 / 카드번호 4분할 / 공통 Input/컴포넌트 합성 / 검증·에러 처리 / 카드사/브랜드 판별 |
| #422 | @thgml05 | 객체/배열 state 구조 / 카드번호 4분할 / 공통 Input/컴포넌트 합성 / 검증·에러 처리 / 카드사/브랜드 판별 |
| #423 | @yeji0214 | state 위치 / 공통 Input/컴포넌트 합성 / 검증·에러 처리 / 카드사/브랜드 판별 |
| #425 | @Db0111 | state 위치 / 객체/배열 state 구조 / 공통 Input/컴포넌트 합성 / 검증·에러 처리 / 카드사/브랜드 판별 |
| #426 | @rosielsh | state 위치 / 객체/배열 state 구조 / 공통 Input/컴포넌트 합성 / 검증·에러 처리 |
| #427 | @sanghee01 | 객체/배열 state 구조 / 카드번호 4분할 / 공통 Input/컴포넌트 합성 / 검증·에러 처리 / 카드사/브랜드 판별 |
| #430 | @yeongipark | state 위치 / 객체/배열 state 구조 / 카드번호 4분할 / 공통 Input/컴포넌트 합성 / 검증·에러 처리 / 카드사/브랜드 판별 |
| #433 | @eunsoA | state 위치 / 객체/배열 state 구조 / 카드번호 4분할 / 공통 Input/컴포넌트 합성 / 검증·에러 처리 / 카드사/브랜드 판별 |
| #435 | @dev-dino22 | state 위치 / 객체/배열 state 구조 / 카드번호 4분할 / 공통 Input/컴포넌트 합성 / 검증·에러 처리 / 카드사/브랜드 판별 |
| #436 | @bunju20 | 카드번호 4분할 / 공통 Input/컴포넌트 합성 / 검증·에러 처리 / 카드사/브랜드 판별 |
| #437 | @aydenote | 객체/배열 state 구조 / 카드번호 4분할 / 공통 Input/컴포넌트 합성 / 검증·에러 처리 / 카드사/브랜드 판별 |
| #438 | @wo-o29 | 객체/배열 state 구조 / 카드번호 4분할 / 공통 Input/컴포넌트 합성 |
| #439 | @kimyou1102 | custom hook / 객체/배열 state 구조 / 카드번호 4분할 / 공통 Input/컴포넌트 합성 / 검증·에러 처리 / 카드사/브랜드 판별 |
| #441 | @hanheel | 카드번호 4분할 / 공통 Input/컴포넌트 합성 / 검증·에러 처리 / 카드사/브랜드 판별 |
| #442 | @jaeyoung-kwon | state 위치 / 공통 Input/컴포넌트 합성 / 카드사/브랜드 판별 |
| #443 | @jin123457 | 카드번호 4분할 / 공통 Input/컴포넌트 합성 / 검증·에러 처리 / 카드사/브랜드 판별 |
| #444 | @mun-kyeong | state 위치 / 객체/배열 state 구조 / 카드번호 4분할 / 공통 Input/컴포넌트 합성 / 검증·에러 처리 / 카드사/브랜드 판별 |
| #446 | @JeLee-river | state 위치 / 객체/배열 state 구조 / 공통 Input/컴포넌트 합성 / 카드사/브랜드 판별 |
| #448 | @hoyyChoi | state 위치 / 객체/배열 state 구조 / 공통 Input/컴포넌트 합성 / 검증·에러 처리 / 카드사/브랜드 판별 |
195개 전체 인덱스(다른 주제 포함)는 부록에서 확인할 수 있습니다.





