Skip to Content
페이먼츠 미션1단계 FAQ 카드Q1. state는 어디서 관리하나

Q1. state(제어)를 어느 컴포넌트에서 관리해야 할까?

크루의 질문

“state 관리(제어)를 어느 컴포넌트에서 해야 할지 오래 고민했습니다. 컴포넌트 쪼개는 기준에 대해 얘기를 많이 했습니다.” — 파라디·피트·이현 페어

“각 입력 필드를 합성하는 최상위 컴포넌트에서 가지고 있을지, custom hook 안의 useState로 가지고 반환값을 사용해서 컴포넌트를 구성할지 고민중입니다.” — 콘티·먼지 페어

“3개 이상의 컴포넌트를 통과하는 상태 props는 전역 상태로 관리하는 것이 좋은가에 대해 논의해보았습니다.” — 지오·코브 페어

AS-IS 코드

🔍 읽기 전에

이 코드는 상태를 어디까지 끌어올렸나요?

하위 컴포넌트가 상태를 그대로 보유했다면 App은 무엇을 모를 수 있었을까요?

// src/App.tsx (PR #439 데이지) import useCardCVC from './hooks/useCardCVC'; const { cardNumber, onChange, checkCardNumberError, isError, errorMessage: cardNumberErrorMessage, } = useCardNumber(); const { cardValidityPeriod, isErrorCardValidityPeriod, onChangeCardValidityPeriod, checkCardValidityPeriodError, errorMessage: cardValidityPeriodErrorMessage, } = useCardValidityPeriod(); const { cardCVC, isCardCVCError, onChangeCVC, checkCardCVCError, errorMessage: cardCVCErrorMessage, } = useCardCVC();

App이 카드번호·만료일·CVC 세 종류 상태를 모두 알고 있다. 자식 컴포넌트들은 props로 받아 쓴다. 왜 여기까지 끌어올렸을까그 비용은 무엇이었을까가 이 카드의 학습 포인트다.

공식문서 단서 — State 끌어올리기

Sharing State Between Components  첫 단락 (한글 번역):

Sometimes, you want the state of two components to always change together. To do it, remove state from both of them, move it to their closest common parent, and then pass it down to them via props. This is known as lifting state up, and it’s one of the most common things you will do writing React code.

핵심 한 줄: 상태를 자식이 공유해야 할 때, 가장 가까운 공통 부모로 옮긴다. 페이먼츠에서는 프리뷰 카드가 카드번호·만료일·소유자명·브랜드를 동시에 보여주므로(CVC는 실제 카드처럼 프리뷰에 노출되지 않습니다), 입력 컴포넌트들과 프리뷰의 공통 부모가 어디인지가 결정의 기준이 된다. 반대로 CVC는 프리뷰가 모르는 값 — 이런 입력은 굳이 App까지 끌어올리지 않아도 되는 후보가 된다.

또한 Choosing the State Structure 의 다섯 원칙 중 첫 번째 — “Group related state. If you always update two or more state variables at the same time, consider merging them into a single state variable.” — 가 Q2와 직결된다.


선배 PR 읽기 가이드

선배 PR 읽기 가이드 — 펼쳐보기

이 영역은 정답 PR을 찾는 곳이 아닙니다. 지금 우리 페어가 어디까지 state를 올렸는지, 그 결정 때문에 어떤 비용을 감수하고 있는지를 선배 PR의 대화로 비춰보는 자리입니다. 코드를 먼저 훑기보다, 리뷰어가 멈춰 세운 질문과 작성자의 답변을 먼저 읽어보세요.

PR #439 데이지 — App으로 끌어올렸을 때 생기는 질문

PR #439 데이지(@kimyou1102)  · 인라인 리뷰 모음 →  — 8기 직전 기수의 PR입니다.

먼저 볼 자리: src/App.tsx:27 인라인 스레드 → 리뷰어가 “CVC 관련 상태는 App이 몰라도 될 것 같습니다. 오히려 알고 있을 때 어떤 단점이 있을까요?” 라고 묻는 지점에서 시작하면 좋습니다.

읽는 관점

  • 이 state를 App이 알아야 하는 기능상 이유가 있었는가? 프리뷰, 제출, 에러 표시처럼 두 영역이 동시에 필요한 정보인지 확인합니다.
  • App으로 올린 뒤 props가 어디까지 퍼졌는가? 자식 컴포넌트가 단순해진 대신 부모가 무엇을 더 많이 알게 됐는지 봅니다.
  • CVC처럼 특정 입력 영역 안에서 끝날 수 있는 state라면, App이 아니라 새 컴포넌트 경계를 만드는 선택지도 있었는지 살핍니다.

페어 대화 포인트

  • 우리 코드에서 “일단 App에 둔 state”를 세어봅니다.
  • 각 state 옆에 누가 읽는가, 누가 바꾸는가, 같이 바뀌어야 하는 컴포넌트가 둘 이상인가를 적어봅니다.
  • “3개 이상 컴포넌트를 지나가니까 전역 상태나 Context가 필요하다”고 판단한 순간이 있었다면, 정말 필요한 공유인지 다시 이야기해봅니다.

PR #361 제이드 — custom hook을 먼저 만들었을 때 생기는 질문

PR #361 제이드(@skiende74)  · 인라인 리뷰 모음 →  — custom hook 추출을 고민 중이라면 특히 참고하기 좋은 PR입니다.

먼저 볼 자리: src/hooks/useInput.tsx 인라인 → 그리고 src/hooks/useInputs.tsx 인라인 →. 리뷰어가 useInput의 존재 이유와 useInputs로 다시 합친 구조를 질문하는 흐름을 따라가면 됩니다.

읽는 관점

  • hook이 실제 중복을 줄이는가, 아니면 state와 handler를 다른 파일로 옮겼을 뿐인가?
  • useInput처럼 넓은 이름보다 useCardNumber처럼 도메인 의미가 남는 이름이 더 읽기 쉬운가?
  • hook으로 합치기보다 카드번호 컴포넌트, 유효기간 컴포넌트처럼 화면의 의미 단위로 나누는 편이 더 자연스러운가?

페어 대화 포인트

  • “훅으로 빼자”는 말이 나왔을 때, 같은 로직이 두 번 이상 반복되고 있는지 먼저 확인합니다.
  • 훅 이름만 보고 그 훅의 책임을 설명할 수 있는지 서로 물어봅니다.
  • 2단계에서 카드사 선택, 별칭, 비동기 저장 같은 요구사항이 늘어나면 이 hook이 바뀔지, 컴포넌트만 바뀔지 예상해봅니다.

비교하며 읽기

  • 데이지 PR은 필요해서 끌어올렸지만 비용을 다시 확인한 사례입니다.
  • 제이드 PR은 미리 추출했지만 추상화의 기준을 다시 세운 사례입니다.
  • 우리 코드는 둘 중 어디에 가까운지 표시해보세요. 이미 너무 많이 끌어올렸는지, 아직 반복을 보기도 전에 훅을 만들고 있는지 구분하는 것만으로도 다음 리팩터링 방향이 또렷해집니다.

자기 가설이 자식이 state를 자체 보유하는 방향이라면 연관 PR 더 보기에서 state 위치만 매핑된 PR(예: #88  코이, #73  앨버, #195  루루)을 골라, 왜 그 구조가 유지되거나 바뀌었는지 비교해보세요.

추가 읽을거리 — Dan Abramov · Kent C. Dodds

외부 글 모음 — 펼쳐보기

이 주제와 이어지는 외부 글입니다.

Kent C. Dodds — Application State Management with React

  • 원문: kentcdodds.com/blog/application-state-management-with-react 
  • 한 줄 요약: Kent는 “React 자체가 상태 관리 라이브러리” 라는 입장에서 순서를 제안한다 — Local → Lifting → Composition(children prop) → Context → 외부 라이브러리. 공유가 필요하면 먼저 state를 필요한 공통 부모로 올리고, prop drilling이 부담될 때는 컴포넌트 합성을 먼저 검토한 뒤 Context를 고려하라는 흐름이다. 지오·코브 페어의 “3단계 이상 props는 전역?” 질문에는 “단계 수만 보지 말고 필요한 공유 범위부터 확인하라” 는 기준으로 읽는 편이 정확하다.

Dan Abramov — Writing Resilient Components

  • 원문: overreacted.io/writing-resilient-components 
  • 한 줄 요약: 컴포넌트가 부모의 변경에 잘 견디려면 어떤 원칙을 따라야 하는가. 끌어올린 state가 자식의 가정과 어긋날 때의 비용. PR #439 데이지가 App에 끌어올린 뒤 인식한 비용과 이어진다.

Kent C. Dodds — AHA Programming

  • 원문: kentcdodds.com/blog/aha-programming 
  • 한 줄 요약: Avoid Hasty Abstractions — 성급한 추상화를 피하라. 페이먼츠 2단계 프로그래밍 요구사항의 *“처음부터 훅 구조를 설계하지 않는다”*는 이 원칙과 같은 방향으로 읽을 수 있다. PR #361 제이드가 useInput을 처음부터 만들었다가 구조를 다시 생각하게 된 사례와 이어진다.

연관 PR 더 보기

이 주제에 매핑된 1단계 PR 전체 — 펼쳐보기

자기 가설에 가까운 PR을 골라 추가로 비교해보세요.

PR작성자핵심 키워드
#6 @Puterismstate 위치 / 공통 Input/컴포넌트 합성 / 카드사/브랜드 판별
#7 @dudtjr913state 위치 / 객체/배열 state 구조 / 공통 Input/컴포넌트 합성
#9 @0307kwonstate 위치 / 객체/배열 state 구조 / 카드번호 4분할 / 카드사/브랜드 판별
#11 @Tanney-102state 위치 / 객체/배열 state 구조 / 카드번호 4분할 / 카드사/브랜드 판별
#29 @swon3210state 위치 / 카드번호 4분할 / 공통 Input/컴포넌트 합성 / 카드사/브랜드 판별
#69 @juunzzistate 위치 / 공통 Input/컴포넌트 합성
#71 @DomMorellostate 위치 / 객체/배열 state 구조 / 카드번호 4분할 / 공통 Input/컴포넌트 합성 / 검증·에러 처리
#72 @jswithstate 위치 / 객체/배열 state 구조
#73 @al-burstate 위치
#74 @LAH1203custom hook / 카드번호 4분할
#75 @intae92state 위치 / 카드번호 4분할
#77 @JUDONGHYEOKstate 위치 / 객체/배열 state 구조 / 카드번호 4분할 / 공통 Input/컴포넌트 합성
#78 @soyi47state 위치 / 객체/배열 state 구조 / 카드번호 4분할 / 공통 Input/컴포넌트 합성
#80 @compy-ryustate 위치 / 검증·에러 처리
#82 @hwangstar156state 위치 / 카드번호 4분할 / 카드사/브랜드 판별
#83 @dayelopstate 위치
#85 @lokbastate 위치 / 객체/배열 state 구조 / 카드사/브랜드 판별
#88 @InKyoJeongstate 위치
#89 @onschanstate 위치 / 객체/배열 state 구조 / 카드번호 4분할 / 검증·에러 처리
#91 @moonheekim0118custom hook / 카드번호 4분할 / 공통 Input/컴포넌트 합성 / 검증·에러 처리
#92 @nan-noostate 위치
#94 @euijinkkstate 위치 / 객체/배열 state 구조 / 카드번호 4분할 / 공통 Input/컴포넌트 합성 / 검증·에러 처리 / 카드사/브랜드 판별
#95 @KangYunHo1221state 위치 / 카드번호 4분할 / 공통 Input/컴포넌트 합성
#96 @jhy979state 위치 / 객체/배열 state 구조 / 카드번호 4분할 / 검증·에러 처리
#97 @kamwoostate 위치 / 카드번호 4분할 / 공통 Input/컴포넌트 합성 / 검증·에러 처리
#98 @byhhh2state 위치 / 객체/배열 state 구조 / 공통 Input/컴포넌트 합성 / 카드사/브랜드 판별
#100 @woose28state 위치 / 카드번호 4분할 / 공통 Input/컴포넌트 합성 / 검증·에러 처리
#101 @sanaandmomostate 위치 / 카드사/브랜드 판별
#102 @liswktjsstate 위치 / 카드번호 4분할 / 검증·에러 처리
#104 @uk960214state 위치 / 객체/배열 state 구조 / 검증·에러 처리
#105 @roncicustom hook / 카드번호 4분할 / 카드사/브랜드 판별
#189 @nlom0218state 위치 / 객체/배열 state 구조 / 카드번호 4분할 / 검증·에러 처리
#190 @dladncks1217state 위치 / 객체/배열 state 구조 / 카드번호 4분할 / 카드사/브랜드 판별
#192 @semnil5202state 위치
#193 @suyoungjstate 위치 / 객체/배열 state 구조 / 카드번호 4분할
#195 @hafnium1923state 위치
#196 @Leejin-Yangstate 위치
#197 @xodms0309state 위치 / 카드번호 4분할 / 공통 Input/컴포넌트 합성
#198 @ashleysyheostate 위치 / 객체/배열 state 구조 / 공통 Input/컴포넌트 합성 / 검증·에러 처리
#199 @guridaekstate 위치 / 카드번호 4분할
#201 @HyeryongChoistate 위치 / 객체/배열 state 구조 / 카드번호 4분할 / 공통 Input/컴포넌트 합성
#203 @nangkyeonglimstate 위치 / 객체/배열 state 구조 / 공통 Input/컴포넌트 합성
#204 @NaveOWOstate 위치 / 객체/배열 state 구조 / 공통 Input/컴포넌트 합성
#205 @2yunseongstate 위치 / 객체/배열 state 구조 / 카드번호 4분할 / 공통 Input/컴포넌트 합성
#206 @turtle601custom hook / 객체/배열 state 구조 / 검증·에러 처리
#207 @inyeong-kangcustom hook / 객체/배열 state 구조 / 공통 Input/컴포넌트 합성 / 검증·에러 처리
#208 @D0Damstate 위치 / 객체/배열 state 구조 / 공통 Input/컴포넌트 합성
#209 @jiwonh423state 위치 / 공통 Input/컴포넌트 합성
#211 @jariitastate 위치 / 객체/배열 state 구조
#212 @jw-rstate 위치 / 객체/배열 state 구조 / 카드번호 4분할
#213 @wzrabbitstate 위치 / 객체/배열 state 구조 / 카드번호 4분할 / 공통 Input/컴포넌트 합성 / 검증·에러 처리
#214 @n0eyescustom hook / 객체/배열 state 구조 / 공통 Input/컴포넌트 합성 / 검증·에러 처리
#215 @Dahyeeeestate 위치 / 객체/배열 state 구조 / 공통 Input/컴포넌트 합성
#216 @yeoptostate 위치 / 검증·에러 처리
#220 @ukkodeveloperstate 위치 / 객체/배열 state 구조
#223 @geuntaek1013state 위치 / 검증·에러 처리
#225 @woo-jkstate 위치 / 공통 Input/컴포넌트 합성 / 검증·에러 처리
#226 @regularParkstate 위치 / 객체/배열 state 구조 / 공통 Input/컴포넌트 합성
#228 @hozzijeongstate 위치 / 객체/배열 state 구조
#230 @gyeongzastate 위치 / 객체/배열 state 구조 / 카드번호 4분할 / 공통 Input/컴포넌트 합성
#232 @Gilpop8663custom hook / 객체/배열 state 구조 / 카드번호 4분할 / 공통 Input/컴포넌트 합성 / 검증·에러 처리
#233 @sh981013sstate 위치 / 객체/배열 state 구조 / 공통 Input/컴포넌트 합성
#234 @yogjinstate 위치 / 객체/배열 state 구조 / 공통 Input/컴포넌트 합성
#331 @anttieystate 위치 / 공통 Input/컴포넌트 합성 / 검증·에러 처리 / 카드사/브랜드 판별
#334 @vi-wolhwastate 위치 / 객체/배열 state 구조 / 카드번호 4분할 / 공통 Input/컴포넌트 합성 / 검증·에러 처리 / 카드사/브랜드 판별
#337 @jinhokim98custom hook / 객체/배열 state 구조 / 카드번호 4분할 / 공통 Input/컴포넌트 합성 / 검증·에러 처리 / 카드사/브랜드 판별
#338 @Largopiecustom hook / 객체/배열 state 구조 / 카드번호 4분할 / 공통 Input/컴포넌트 합성 / 검증·에러 처리 / 카드사/브랜드 판별
#339 @Yoonkyoungmestate 위치 / 공통 Input/컴포넌트 합성 / 검증·에러 처리
#341 @simorimistate 위치 / 객체/배열 state 구조 / 카드번호 4분할 / 공통 Input/컴포넌트 합성 / 검증·에러 처리 / 카드사/브랜드 판별
#343 @brgndyycustom hook / 객체/배열 state 구조 / 카드번호 4분할 / 공통 Input/컴포넌트 합성 / 검증·에러 처리 / 카드사/브랜드 판별
#344 @soi-hastate 위치 / 객체/배열 state 구조 / 카드번호 4분할 / 검증·에러 처리 / 카드사/브랜드 판별
#346 @chlwlstlfstate 위치 / 카드사/브랜드 판별
#348 @pp449state 위치 / 객체/배열 state 구조 / 카드번호 4분할 / 공통 Input/컴포넌트 합성 / 검증·에러 처리 / 카드사/브랜드 판별
#349 @BadaHertz52state 위치 / 객체/배열 state 구조 / 카드번호 4분할 / 공통 Input/컴포넌트 합성 / 검증·에러 처리
#352 @Hain-tainstate 위치
#353 @ooherincustom hook / 객체/배열 state 구조 / 카드번호 4분할 / 공통 Input/컴포넌트 합성 / 검증·에러 처리
#354 @hwinkrstate 위치 / 객체/배열 state 구조 / 공통 Input/컴포넌트 합성 / 검증·에러 처리 / 카드사/브랜드 판별
#357 @00kangstate 위치 / 객체/배열 state 구조 / 카드번호 4분할 / 공통 Input/컴포넌트 합성 / 검증·에러 처리 / 카드사/브랜드 판별
#358 @dle234state 위치 / 검증·에러 처리 / 카드사/브랜드 판별
#359 @rbgksqkrcustom hook / 카드번호 4분할 / 공통 Input/컴포넌트 합성 / 검증·에러 처리 / 카드사/브랜드 판별
#361 @skiende74 (대표)custom hook / 객체/배열 state 구조 / 공통 Input/컴포넌트 합성 / 검증·에러 처리 / 카드사/브랜드 판별
#363 @chysisstate 위치 / 공통 Input/컴포넌트 합성 / 카드사/브랜드 판별
#366 @Parkhanyoungcustom hook / 카드번호 4분할 / 검증·에러 처리 / 카드사/브랜드 판별
#367 @ss0526100custom hook / 객체/배열 state 구조 / 검증·에러 처리 / 카드사/브랜드 판별
#409 @keemsebinstate 위치 / 객체/배열 state 구조 / 카드사/브랜드 판별
#411 @AHHYUNJUstate 위치 / 카드번호 4분할 / 검증·에러 처리 / 카드사/브랜드 판별
#412 @mlnwnsstate 위치 / 객체/배열 state 구조 / 카드번호 4분할 / 검증·에러 처리 / 카드사/브랜드 판별
#413 @Beomtaecustom hook / 카드번호 4분할 / 공통 Input/컴포넌트 합성 / 검증·에러 처리
#414 @ohguscustom hook / 객체/배열 state 구조 / 카드번호 4분할 / 공통 Input/컴포넌트 합성 / 검증·에러 처리
#416 @jeongyoustate 위치 / 객체/배열 state 구조 / 카드번호 4분할 / 공통 Input/컴포넌트 합성 / 검증·에러 처리
#417 @sooyeoniyacustom hook / 카드번호 4분할 / 공통 Input/컴포넌트 합성 / 검증·에러 처리 / 카드사/브랜드 판별
#418 @MinSungJestate 위치 / 객체/배열 state 구조 / 카드번호 4분할 / 카드사/브랜드 판별
#420 @ShinjungOhstate 위치 / 카드번호 4분할 / 공통 Input/컴포넌트 합성 / 검증·에러 처리 / 카드사/브랜드 판별
#421 @ExceptAnyonestate 위치 / 검증·에러 처리 / 카드사/브랜드 판별
#423 @yeji0214state 위치 / 공통 Input/컴포넌트 합성 / 검증·에러 처리 / 카드사/브랜드 판별
#425 @Db0111state 위치 / 객체/배열 state 구조 / 공통 Input/컴포넌트 합성 / 검증·에러 처리 / 카드사/브랜드 판별
#426 @rosielshstate 위치 / 객체/배열 state 구조 / 공통 Input/컴포넌트 합성 / 검증·에러 처리
#428 @kaori-killercustom hook / 검증·에러 처리
#430 @yeongiparkstate 위치 / 객체/배열 state 구조 / 카드번호 4분할 / 공통 Input/컴포넌트 합성 / 검증·에러 처리 / 카드사/브랜드 판별
#431 @eunwoo-levistate 위치 / 객체/배열 state 구조 / 검증·에러 처리
#433 @eunsoAstate 위치 / 객체/배열 state 구조 / 카드번호 4분할 / 공통 Input/컴포넌트 합성 / 검증·에러 처리 / 카드사/브랜드 판별
#434 @minji2219state 위치 / 카드번호 4분할 / 검증·에러 처리 / 카드사/브랜드 판별
#435 @dev-dino22state 위치 / 객체/배열 state 구조 / 카드번호 4분할 / 공통 Input/컴포넌트 합성 / 검증·에러 처리 / 카드사/브랜드 판별
#439 @kimyou1102 (대표)custom hook / 객체/배열 state 구조 / 카드번호 4분할 / 공통 Input/컴포넌트 합성 / 검증·에러 처리 / 카드사/브랜드 판별
#440 @dlsxjzldcustom hook / 객체/배열 state 구조 / 카드번호 4분할 / 검증·에러 처리
#442 @jaeyoung-kwonstate 위치 / 공통 Input/컴포넌트 합성 / 카드사/브랜드 판별
#444 @mun-kyeongstate 위치 / 객체/배열 state 구조 / 카드번호 4분할 / 공통 Input/컴포넌트 합성 / 검증·에러 처리 / 카드사/브랜드 판별
#445 @Daeun-100state 위치 / 카드번호 4분할 / 검증·에러 처리 / 카드사/브랜드 판별
#446 @JeLee-riverstate 위치 / 객체/배열 state 구조 / 공통 Input/컴포넌트 합성 / 카드사/브랜드 판별
#447 @shuyeonstate 위치 / 객체/배열 state 구조 / 카드사/브랜드 판별
#448 @hoyyChoistate 위치 / 객체/배열 state 구조 / 공통 Input/컴포넌트 합성 / 검증·에러 처리 / 카드사/브랜드 판별
#450 @Daeun-100state 위치 / 검증·에러 처리
#452 @kaori-killerstate 위치 / 검증·에러 처리
#453 @ExceptAnyonestate 위치 / 검증·에러 처리 / 카드사/브랜드 판별

195개 전체 인덱스(다른 주제 포함)는 부록에서 확인할 수 있습니다.

Last updated on