붕어빵 틀과 붕어빵으로 이해하는 리액트: 기획자를 위한 쉬운 데이터 설명서
붕어빵 틀과 붕어빵으로 이해하는 리액트: 기획자를 위한 쉬운 데이터 설명서
개발자와 회의를 하다 보면 “그건 Props로 넘기면 되는데, State 관리가 복잡해지겠네요” 같은 말을 듣곤 합니다. 컴포넌트(Component)가 무엇인지 겨우 이해했더니, 이제는 그 안에서 움직이는 데이터가 발목을 잡죠.
기획자가 리액트 코드를 짤 필요는 없습니다. 하지만 데이터가 어떻게 흐르는지만 이해해도 화면의 기획 의도를 개발자에게 훨씬 명확하게 전달할 수 있습니다. 오늘은 우리에게 친숙한 ‘붕어빵’ 비유로 핵심 개념을 한 번에 정리해 봅시다. 🐟
핵심 요약 (30초 컷)
- Props: 붕어빵의 ‘주문서/재료’ 같은 설정값(자식 입장에서는 읽기 전용)
- State: 붕어빵의 ‘온도’처럼 내부에서 변하는 상태값(변하면 화면 재렌더링)
- 데이터 흐름: React는 기본적으로 부모 → 자식 단방향으로 내려간다
- State 끌어올리기: 여러 화면에 반영되면 공통 부모가 State를 들고 Props로 전달
1. 리액트에서 ‘데이터’를 이해해야 하는 이유
React 화면은 “그림을 잘 그리면 끝”이 아니라, 데이터가 바뀌면 화면이 자동으로 바뀌는 구조입니다. 그래서 기획서도 화면 설명만 있으면 부족하고, 최소한 아래 두 가지는 읽혀야 개발자가 질문 없이 착수할 수 있습니다.
- 이 UI는 어떤 설정값(Props)을 받아서 그려지는가?
- 사용자 행동으로 어떤 상태(State)가 바뀌며, 그때 화면이 어떻게 달라지는가?
이제부터 붕어빵 세계관으로 간단하고 정확하게 정리해 볼게요. (배고프면 성공) 🍞
2. Props: 붕어빵의 ‘주문서’ (변하지 않는 속성)
React에서 Props(Properties)는 부모 컴포넌트가 자식 컴포넌트에게 전달하는 설정값입니다. 붕어빵 가게로 치면, 붕어빵 틀은 컴포넌트이고, 주문자가 선택한 재료(팥/슈크림/잡채)가 Props입니다.
Props의 핵심 특징(기획자가 기억할 것)
- 읽기 전용(Read-only): 붕어빵이 굽기 시작하면 속재료를 바꿀 수 없듯, 자식 컴포넌트는 받은 Props를 수정하지 않습니다.
- 재사용의 핵심: 틀(컴포넌트)은 그대로 두고 재료(Props)만 바꿔 여러 UI를 만들 수 있습니다.
기획자 사고 방식 예시(바로 써먹는 문장)
- “이 버튼 컴포넌트에는 label=확인과 theme=blue를 Props로 내려주세요.”
- “이 카드 컴포넌트는 title/price/badge를 Props로 받아 동일 레이아웃을 재사용합니다.”
3. State: 붕어빵의 ‘온도’ (살아 움직이는 상태)
반면 State는 컴포넌트 내부에서 스스로 관리하고 변화시키는 데이터입니다. 붕어빵이 갓 구워졌을 때는 뜨겁다가 시간이 지나면 식어버리죠. 이 ‘현재 온도’는 외부에서 정해주는 게 아니라 붕어빵(컴포넌트) 내부 상태입니다.
State의 핵심 특징(기획자가 기억할 것)
- 변하면 화면이 다시 그려짐(Re-rendering): 온도가 낮아지면 김이 사라지듯, State 변화는 UI 변화를 일으킵니다.
- 사용자 인터랙션과 직결: 클릭/입력/선택/로드 결과 같은 “움직이는 값” 대부분이 State입니다.
State 예시(실무에서 제일 자주 만나는 것들)
- 체크박스 체크 여부
- 입력창에 타이핑 중인 글자
- 장바구니 수량
- 로딩 여부(isLoading), 에러 여부(isError), 빈 화면 여부(isEmpty)
4. 기획자가 꼭 기억해야 할 데이터 흐름의 법칙(부모→자식)
React는 기본적으로 데이터가 위에서 아래로(부모 → 자식) 흐르는 단방향 구조를 가집니다. 붕어빵 가게로 치면, “사장님(부모)”이 주문서를 내려주고, “붕어빵(자식)”은 그 주문에 따라 만들어집니다.
| 구분 | Props (설정값) | State (상태값) |
|---|---|---|
| 관리 주체 | 부모(주문하는 사장님) | 나(구워지는 붕어빵) |
| 가변성 | 전달받으면 변경 불가(읽기 전용) | 스스로 언제든 변경 가능 |
| 화면 영향 | Props가 바뀌면 새 재료로 다시 굽는 느낌(다시 렌더링될 수 있음) | State가 바뀌면 화면이 다시 그려짐(Re-rendering) |
| 기획 예시 | 버튼의 이름, 팝업의 제목, 카드의 가격 | 탭 선택 인덱스, 로딩 여부, 체크 여부 |
💡 기획 Tip
“A 화면에서 바꾼 값이 B 화면에도 반영되어야 해요”라면, 두 화면의 공통 부모가 그 데이터를 State로 들고 있어야 합니다. 개발자에게 “이 데이터는 어디서 관리(State)되어야 할까요?”라고 질문해 보세요. 소통의 격이 달라집니다.
5. (그림으로 끝) 상위로 State 끌어올리기: “한 번 바꾼 값이 다른 화면에도 반영”되는 구조
기획에서 가장 자주 나오는 요구사항이 이거죠: “A 화면에서 바꾼 값이 B 화면에도 반영돼야 해요.” 이때 개발자들이 말하는 정답 패턴이 State 끌어올리기(Lifting State Up)입니다.
붕어빵 비유로 바꾸면 이렇게 됩니다. 각 붕어빵(자식)이 제각각 “온도(State)”를 들고 있으면, 한 붕어빵이 식었다고 옆 붕어빵의 온도까지 같이 바뀌진 않죠. 그래서 사장님(공통 부모)이 “오늘의 가게 기준 온도”를 장부(State)로 들고 있고, 각 붕어빵에게는 “현재 온도 정보(Props)”를 내려주는 방식이 깔끔합니다.
텍스트 도식 1) 가장 많이 쓰는 구조(부모가 State를 들고, 자식은 Props로 받기)
[사장님(Parent)] ← State 보관소(장부)
- sharedState: 예) selectedTab, cartCount, isLoggedIn
- setSharedState: 값을 바꾸는 버튼(업데이트 함수)
│ Props로 내려줌(주문서 전달)
▼
[붕어빵 A(Child A)] [붕어빵 B(Child B)]
- props.sharedState - props.sharedState
- A에서 변경 필요 시 - 동일 값 반영
"변경 요청"을 위로 올림
▲
│ 콜백(요청서)로 올림: onChange(...)
└────────────────────────────────
텍스트 도식 2) “A에서 바꾸면 B도 바뀌는” 흐름을 한 줄로
A에서 액션 발생 → 부모에게 변경 요청(onChange) → 부모 State 변경
→ 부모가 A/B에 Props로 재전달 → A/B 화면이 함께 업데이트
기획서에 그대로 붙여 넣는 문장(개발자와 바로 합의되는 표현)
- “이 값은 A와 B에 동시에 반영되어야 하므로, 공통 부모에서 State로 관리하고 각 화면에는 Props로 전달합니다.”
- “A에서 변경 이벤트가 발생하면, 상위에서 상태를 업데이트하고 B에서도 같은 값이 즉시 반영되어야 합니다.”
- “이 값은 화면 로컬이 아니라 공유 상태이므로, State 위치(관리 주체)를 상위로 올려주세요.”
실무 Tip: “상위로 올릴지” 10초 판단 질문
- 이 값이 두 개 이상 화면/영역에 영향을 주나요? → 예면 상위 관리 가능성 ↑
- 이 값이 바뀌면 다른 컴포넌트가 같이 반응해야 하나요? → 예면 상위 관리 가능성 ↑
- 이 값이 특정 컴포넌트 내부에서만 의미가 있나요? → 예면 로컬 State 유지 가능성 ↑
6. (실전 예시) 장바구니 수량이 모든 화면에 반영되게 하려면? = State를 공통 부모로 끌어올리기
기획에서 자주 나오는 요구사항이 이거예요:
“상품 상세에서 장바구니에 담으면, 헤더의 장바구니 뱃지(수량)도 바로 바뀌어야 해요.”
이건 화면 하나의 문제가 아니라, 여러 영역이 같은 데이터를 공유해야 하는 문제입니다.
요구사항을 React 언어로 번역하면?
- 공유 데이터: cartCount(장바구니 담긴 개수)
- 변경 트리거: “담기” 버튼 클릭, 삭제/수량 변경, 서버 응답 성공
- 영향 범위(UI): 헤더 뱃지, 장바구니 리스트, 결제 요약
붕어빵 비유로 이해하기
붕어빵(각 화면/컴포넌트)이 자기 온도(State)를 들고 있으면, 한 붕어빵을 데웠다고 옆 붕어빵이 같이 따뜻해지진 않죠. 그래서 사장님(공통 부모)이 “오늘 가게의 장바구니 수량 장부(State)”를 들고, 헤더/상세/장바구니 화면에는 그 값을 Props로 내려주는 구조가 필요합니다.
텍스트 도식: 어디에 State를 둬야 A에서 바꿔도 B에 반영될까?
[App 또는 Layout(공통 부모)]
State: cartCount, cartItems, isCartSyncing
Action: setCartCount / setCartItems
│ Props로 내려줌
├──────────────► [Header]
│ props.cartCount → 뱃지 수량 표시
│
├──────────────► [ProductDetail]
│ "담기" 클릭 → onAddToCart() 호출(부모로 요청)
│
└──────────────► [CartPage]
props.cartItems → 목록 표시
수량 변경/삭제 → onUpdateCart() 호출(부모로 요청)
이벤트 흐름(한 줄로)
상품 상세에서 “담기” 클릭 → 부모에게 변경 요청(onAddToCart)
→ 서버 성공 응답 → 부모 State(cartCount/cartItems) 업데이트
→ Header/CartPage에 Props 재전달 → 뱃지/목록이 즉시 갱신
기획서에 바로 쓰는 문장(개발자와 합의되는 표현)
- “장바구니 수량(cartCount)은 헤더 뱃지/상세/장바구니 화면에 공통 반영되어야 하므로 공통 부모(App/Layout)에서 State로 관리하고 각 화면에는 Props로 전달합니다.”
- “상품 상세에서 ‘담기’ 클릭 시 onAddToCart로 상위에 변경 요청하고, 서버 성공 후 cartCount/cartItems가 업데이트되면 헤더 뱃지가 즉시 갱신되어야 합니다.”
예외 케이스(여기 적어두면 질문이 줄어듭니다)
- 로딩: 담기 요청 중 버튼은 loading 처리(중복 클릭 방지), 헤더 뱃지는 유지
- 실패: 실패 시 toast 노출 + 수량 미변경(롤백), 재시도 가능
- 동기화: 앱 재진입 시 서버 장바구니 조회 후 cartCount 동기화
10초 점검 질문(이 값, 상위로 올려야 할까?)
- cartCount가 두 군데 이상에서 동시에 보여야 하나요? (예: Header + CartPage) → 예
- 어느 한 곳에서 바꾸면 다른 곳도 즉시 반응해야 하나요? → 예
- 그렇다면 이 값은 화면 로컬이 아니라 공유 State입니다 → 상위 관리
7. 기획서에 바로 쓰는 문장 템플릿(실무 Tip)
Props를 명확히 하는 문장
- “이 컴포넌트는 title/description을 Props로 받아 동일 레이아웃으로 재사용합니다.”
- “버튼은 label과 variant를 Props로 내려받습니다(Primary/Secondary).”
State 변화 조건을 명확히 하는 문장
- “클릭 시 isActive가 true로 바뀌고 활성화 스타일이 적용됩니다.”
- “조회 시작 시 isLoading=true, 성공/실패 응답 시 false로 변경됩니다.”
- “에러 발생 시 isError=true이며 토스트를 노출합니다(재시도 버튼 포함).”
화면 간 반영(공통 부모 State) 설명 문장
- “A 화면에서 변경된 값이 B 화면에도 즉시 반영되어야 하므로, 상위 레벨에서 State로 관리 후 하위로 Props로 전달합니다.”
8. 기획자 셀프 체크리스트(Props/State 구분)
- 이 값은 “설정값(Props)”인가, “사용자 행동으로 변하는 값(State)”인가?
- 여러 화면/컴포넌트에서 공유되어야 하는가? (공유면 상위로 올릴 가능성↑)
- 이 값이 바뀔 때 화면은 무엇이 달라져야 하는가? (리렌더링 조건)
- 로딩/에러/빈 화면 같은 예외 상태가 필요한가?
9. 자주 묻는 질문(FAQ)
Q Props와 State의 가장 큰 차이는 무엇인가요?
A Props는 부모가 내려주는 설정값(읽기 전용)이고, State는 컴포넌트 내부에서 변하는 상태값입니다. State가 변하면 화면이 다시 렌더링됩니다.
Q 기획자는 어디까지 알아야 하나요?
A 코드를 작성할 필요는 없지만, 데이터가 “어디서 관리되는지(State 위치)”와 화면이 “무엇을 Props로 받는지”를 설명할 수 있으면 협업 질문이 크게 줄어듭니다.
Q A 화면에서 바꾼 값이 B 화면에도 반영되어야 하면 어떻게 하나요?
A 두 화면의 공통 부모(상위 컴포넌트)가 그 값을 State로 관리하고, 필요한 자식 화면에 Props로 내려주는 구조가 일반적입니다.