8기 페어 고민 → 8장 카드로 어떻게 정리했나
들어가며
8기 크루 12쌍이 페이먼츠 1단계 페어 진행 중에 적어 보낸 고민을 그대로 정리하고, 그것이 어떻게 8장의 카드(Q1~Q8)로 묶였는지를 보여주는 페이지입니다.
같은 미션을 풀면서 여러 페어가 비슷한 고민을 반복했다는 사실은, 페이먼츠 1단계에서 함께 짚어볼 학습 포인트를 보여줍니다. 그래서 8장 카드는 12쌍 페어의 고민에서 자연스럽게 떠오른 주제입니다.
자기 페어의 고민이 어떤 주제와 연결되는지 추적할 수 있도록 했습니다.
1. 12쌍 페어의 고민 — 원본
슬랙에 적어 보낸 그대로입니다. 정리되지 않은 표현이 더 좋다는 생각으로 다듬지 않았습니다.
파라디·피트·이현
- state 관리(제어)를 어느 컴포넌트에서 해야 할지 오래 고민했습니다.
- 컴포넌트 쪼개는 기준에 대해 얘기를 많이 했습니다.
라바·찰리
- 카드 정보를 입력하는 input 컴포넌트에서 최대 길이 제한을 위해 maxLength를 받도록 했는데, input에서 maxLength를 설정하려면 type=‘number’가 불가능해서 문자열 입력이 가능한 상태가 되었다. 결국 maxLength를 선택하고 문자열 입력을 막는 쪽으로 갔는데, input의 범용성이 떨어져서 좋은 선택인지 모르겠다.
- 각 input에 들어가는 카드 정보들을 각각의 state로 관리해야 할지, 하나의 state에서 배열로 관리하고 각 input에서 index 정보를 알게 한 뒤 setter를 호출할지 고민이다.
지오·코브
- 3개 이상의 컴포넌트를 통과하는 상태 props는 전역 상태로 관리하는 것이 좋은가에 대해 논의했다.
콘티·먼지
- 공통 fieldset 컴포넌트를 사용해서 카드번호·유효기간·CVC 컴포넌트를 만들고 payment에서 합성하여 사용했는데, value 상태와 유효성 검사 값이 payment에 있다. 공통 fieldset 컴포넌트가 필요한지 궁금하다.
- 카드번호·유효기간·CVC 같은 사용자 입력 값들의 상태를 저장하는 곳을 고민중이다 — 각 입력 필드를 합성하는 최상위 컴포넌트에 둘지, custom hook 안의 useState로 가지고 반환값으로 컴포넌트를 구성할지.
윤돌·비비빙
- 각 input에 들어가는 정보에 대해서 state를 어떤 구조로 관리할지 고민했다.
- 에러 책임을 어떤 컴포넌트에서 관리할지 고민했다.
포도·레스
- 브랜드 로직은 어디에서 알고 있는 게 맞는가.
도넛·두부
- 비슷한 여러 상태 데이터를 하나로 만들어야 할지 각각 만들어야 할지 (카드번호/유효기간/CVC).
- 하나의 데이터(카드번호)이지만 input이 4개인 경우, 상태를 나누는 것이 맞을까?
클라우디·해니
- 첫번째 input 4자, 2번째 2자, 3번째 4자, 4번째 4자로 총 14자의 카드번호를 받았을 때, 결국 하나의 문자열로 이어붙여 다루게 된다. 카드 미리보기에서도 빠진 자리가 가장 뒤에 있다고 표시될 것 같은데, 굳이 카드 번호를 4개 영역으로 나눠 관리해야 하는지 고민이 든다.
아지·애니
- input의 검증 규칙 및 로직을 어디에서 관리해야 할지.
- 카드 번호 input을 어떤 구조(단일 string, string[], object)로 관리해야 할지.
- cardBrand 값을 formValue로써 관리해야 할지 별도 변수로 관리해야 할지.
안톨리니·벤지
- 아직은 없는 거 같다. 둘 다 빠르게 기능 구현을 먼저 해야 한다는 주의다 (쓰레기부터…). 설계 단계에서 당장 해결책이 떠오르지 않으면서 깊은 고민이 필요한 부분은, 이후 실제 상황과 마주했을 때 전체 구조를 봐가며 남은 시간 속에서 생각해보고 싶다.
유월·이스타
- 상태관리를 어떤 구조로 해야 할지 고민중이다. 이에 따라 사전에 설계한 컴포넌트 구조를 어떻게 변경해야 할지도 고민이 된다.
루멘·디움
- 리액트 자체 사용에는 어려움이 없었으나 타입을 쓰는 과정에서 에러를 많이 만났다. 가장 최근에는 errormode 상태를 만들어서 에러 메시지를 띄우려 했는데, 타입을 너무 넓게 잡아서 조건부 렌더링에서 never 타입이 뜨는 문제가 있었다. 비슷한 결의 타입 좁히기 문제를 해결하는 데 시간이 가장 많이 들었다.
2. 비슷한 고민을 한 페어들 — 분류 표
같은 고민이 몇 페어에서 반복되었는지가 학습 포인트를 찾는 단서입니다.
| 학습 포인트 | 비슷한 고민을 한 페어 | 연결된 카드 |
|---|---|---|
| state를 어느 컴포넌트에서 관리하나 | 파라디 / 콘티·먼지 / 지오·코브 | Q1 |
| 여러 input 상태를 묶을까 나눌까 | 라바 / 윤돌·비비빙 / 도넛·두부 / 아지·애니 / 유월·이스타 | Q2 |
| 카드번호 4영역 분할 vs 단일 | 클라우디·해니 / 도넛·두부 | Q3 |
| 공통 Input/fieldset 컴포넌트 합성 | 콘티·먼지 / 파라디 | Q4 |
| 검증 로직과 에러 책임 위치 | 윤돌·비비빙 / 아지·애니 | Q5 |
| 카드 브랜드 식별 — 폼 vs 도메인 | 포도·레스 / 아지·애니 | Q6 |
| input 제약: maxLength vs type=number | 라바·찰리 | Q7 |
| TypeScript 타입 좁히기 (never) | 루멘·디움 | Q8 |
| (X) 메타 학습 전략: 쓰레기부터 만들기 | 안톨리니·벤지 | 카드 외 — 03회차 도입에서 메타로 다룸 |
3. 어떻게 8장으로 묶었나 — 고민의 흐름
12쌍의 고민을 살펴보면 네 종류의 학습 포인트로 자연스럽게 묶입니다.
A. state를 어디에 두고, 어떻게 묶을까 (Q1·Q2·Q3)
12쌍 중 9쌍이 이 범주에 들어옵니다. 페이먼츠 1단계에서 가장 많이 반복된 학습 포인트입니다.
- 어디에 둘까 (Q1): 자식 vs 부모 vs custom hook
- 어떻게 묶을까 (Q2): 개별 vs 객체 vs 배열
- 분할 vs 단일 (Q3): UI 단위 ≠ 데이터 단위
세 카드는 같은 상태 설계 문제의 다른 각도입니다.
B. 컴포넌트와 책임을 어떻게 나눌까 (Q4·Q5)
- 합성의 단위 (Q4): 공통 컴포넌트 vs 도메인 영역별
- 검증·에러 책임 (Q5): 자식 vs 부모 vs hook
A에서 상태를 정한 뒤, B에서 그 상태를 누가 가지고 누가 보여줄지를 나눕니다.
C. 도메인 규칙은 어디 둘까 (Q6)
- 카드 브랜드 — React가 모르는 영역. 도메인 모듈로 분리할 수 있나.
A·B가 React 컴포넌트 안에서의 결정이라면, C는 React 바깥의 도메인 규칙에 가깝습니다. 1단계에서 지금 분리해두면 2단계 비동기/3단계 hook 추출에서도 변경 범위가 줄어듭니다.
D. 도구 자체를 이해하기 (Q7·Q8)
- input 제약 (Q7): React 영역이 아니라 HTML 표준 영역. maxLength vs type=number는 플랫폼이 만든 trade-off.
- TypeScript 타입 좁히기 (Q8): React 영역이 아니라 언어 자체 영역. errormode union이 never로 좁혀지는 문제.
A·B·C가 React로 구조를 설계하는 문제라면, D는 HTML·TypeScript라는 도구의 규칙을 이해하는 문제입니다. 페이먼츠 1단계의 코드는 React만으로 설명되지 않습니다.
4. 학습 흐름 — 카드 → 부록
각 카드는 자기 코드와 비교할 기준을 마련하는 자료입니다. 각자 자기 페어가 묶인 카드를 펼쳐서:
- 크루의 질문 — 자기 페어 + 비슷한 고민을 한 다른 페어
- AS-IS 코드 — 선배 PR에서 발췌한 한 패턴
- 공식문서 단서 — React 공식문서가 무엇을 말하는지
- 선배 PR 읽기 가이드 — 서로 다른 방식으로 풀어낸 선배 PR 2~3개 (단서: 리뷰어 코멘트 키워드)
- 연관 PR 더 보기 — 같은 주제로 매핑된 다른 PR들
자기 가설에 가장 가까운 PR을 더 비교하고 싶다면 부록 — 1단계 PR 전체 인덱스에서 195개 PR 매핑 표를 펼쳐볼 수 있습니다.
이 페이지는 왜 8장 카드인가를 보여주는 정리 자료입니다. 다른 지점에서 막혔다면 — 그 고민이 12쌍 안에 없는 새 주제라면 — 다음 회차의 카드 후보가 됩니다.




