Skip to content

Conversation

@sueonnn
Copy link
Contributor

@sueonnn sueonnn commented Dec 14, 2025

๐Ÿ“ ๋ฏธ์…˜ ๋ฒˆํ˜ธ

9์ฃผ์ฐจ Misson 1,2,3

๐Ÿ“‹ ๊ตฌํ˜„ ์‚ฌํ•ญ

-Redux Toolkit ํ™œ์šฉ
-Modal Slice ํ™œ์šฉํ•˜์—ฌ, ๋ชจ๋‹ฌ ๊ธฐ๋Šฅ ์ถ”๊ฐ€
-Redux Toolkit์œผ๋กœ ๋งŒ๋“  UMC Play List๋ฅผ Zustand๋กœ ๋ฆฌํŒฉํ† ๋ง

๐Ÿ“Ž ์Šคํฌ๋ฆฐ์ƒท

2025-12-14.10.12.57.mov

โœ… ์ฒดํฌ๋ฆฌ์ŠคํŠธ

  • [0] Merge ํ•˜๋ ค๋Š” ๋ธŒ๋žœ์น˜๊ฐ€ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์„ค์ •๋˜์–ด ์žˆ๋‚˜์š”?
  • [0] ๋กœ์ปฌ์—์„œ ์‹คํ–‰ํ–ˆ์„ ๋•Œ ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•˜์ง€ ์•Š๋‚˜์š”?
  • [0] ๋ถˆํ•„์š”ํ•œ ์ฃผ์„์ด ์ œ๊ฑฐ๋˜์—ˆ๋‚˜์š”?
  • [0] ์ฝ”๋“œ ์Šคํƒ€์ผ์ด ์ผ๊ด€์ ์ธ๊ฐ€์š”?

๐Ÿค” ์งˆ๋ฌธ ์‚ฌํ•ญ

@sueonnn sueonnn requested a review from woojo230 December 14, 2025 12:59
@sueonnn sueonnn self-assigned this Dec 14, 2025
@github-actions
Copy link

github-actions bot commented Dec 14, 2025

๐Ÿค– Gemini ์ฝ”๋“œ๋ฆฌ๋ทฐ ๊ฒฐ๊ณผ

์ฝ”๋“œ ํ†ตํ•ฉ ๋ฆฌ๋ทฐ: ์žฅ๋ฐ”๊ตฌ๋‹ˆ ๊ธฐ๋Šฅ ๊ตฌํ˜„ PR

์•ˆ๋…•ํ•˜์„ธ์š”! ์‹œ๋‹ˆ์–ด ํ”„๋ก ํŠธ์—”๋“œ ๊ฐœ๋ฐœ์ž๋กœ์„œ ์ œ์ถœํ•ด์ฃผ์‹  Pull Request ๋ณ€๊ฒฝ์‚ฌํ•ญ์„ ๋ฉด๋ฐ€ํžˆ ๊ฒ€ํ† ํ–ˆ์Šต๋‹ˆ๋‹ค.
์ด๋ฒˆ PR์€ ์žฅ๋ฐ”๊ตฌ๋‹ˆ ๊ธฐ๋Šฅ์„ Redux Toolkit๊ณผ Zustand๋ฅผ ํ™œ์šฉํ•˜์—ฌ ๊ตฌํ˜„ํ•œ ๊ฒƒ์œผ๋กœ ๋ณด์ž…๋‹ˆ๋‹ค. ์ „๋ฐ˜์ ์œผ๋กœ TypeScript๋ฅผ ์ ๊ทน์ ์œผ๋กœ ํ™œ์šฉํ•˜๊ณ  ์žˆ์œผ๋ฉฐ, ์ปดํฌ๋„ŒํŠธ ๊ตฌ์กฐ๋Š” ๋น„๊ต์  ์ž˜ ๋ถ„๋ฆฌ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค.

ํ•˜์ง€๋งŒ ํ˜„์žฌ ์ฝ”๋“œ์—๋Š” ๋‘ ๊ฐ€์ง€ ์ƒํƒœ ๊ด€๋ฆฌ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ(Redux Toolkit๊ณผ Zustand) ์ฝ”๋“œ๊ฐ€ ๋ชจ๋‘ ํฌํ•จ๋˜์–ด ์žˆ์œผ๋ฉฐ, ์‹ค์ œ UI ์ปดํฌ๋„ŒํŠธ์—์„œ๋Š” ์ฃผ๋กœ Zustand๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉํ–ฅ์œผ๋กœ ๊ตฌํ˜„์ด ์ง„ํ–‰๋œ ์ ์ด ๊ฐ€์žฅ ํฐ ๋ฌธ์ œ์ ์œผ๋กœ ํŒŒ์•…๋ฉ๋‹ˆ๋‹ค. ์ด ์ ์„ ํฌํ•จํ•˜์—ฌ ํ”„๋กœ์ ํŠธ ์„ค์ •, src ๋””๋ ‰ํ† ๋ฆฌ ๋‚ด .ts ๋ฐ .tsx ํŒŒ์ผ๋“ค์„ ์ค‘์‹ฌ์œผ๋กœ ์ƒ์„ธํ•œ ํ”ผ๋“œ๋ฐฑ์„ ๋“œ๋ฆฝ๋‹ˆ๋‹ค.


[์ข…ํ•ฉ ์š”์•ฝ ๋ฐ ๊ฐ€์žฅ ์ค‘์š”ํ•œ ๊ฐœ์„  ์ œ์•ˆ]

  1. ์ƒํƒœ ๊ด€๋ฆฌ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์ผ์›ํ™” (Zustand๋กœ ํ†ต์ผ ๊ถŒ์žฅ)

    • ๋ฌธ์ œ์ : src/slices, src/store/store.ts, src/hooks/useCustomRedux.ts ๋“ฑ Redux Toolkit ๊ด€๋ จ ํŒŒ์ผ๋“ค์ด ์กด์žฌํ•˜์ง€๋งŒ, CartItem.tsx, CartList.tsx, Navbar.tsx, Modal.tsx ๋“ฑ ๋Œ€๋ถ€๋ถ„์˜ UI ์ปดํฌ๋„ŒํŠธ๋“ค์€ src/store/useCartStore.ts (Zustand)๋ฅผ ํ†ตํ•ด ์ƒํƒœ๋ฅผ ๊ด€๋ฆฌํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ํ˜ผ์šฉ์€ ์ฝ”๋“œ์˜ ๋ณต์žก์„ฑ์„ ์ฆ๊ฐ€์‹œํ‚ค๊ณ , ๋ถˆํ•„์š”ํ•œ ์˜์กด์„ฑ์„ ์œ ๋ฐœํ•˜๋ฉฐ, ๊ฐœ๋ฐœ์ž์˜ ํ˜ผ๋ž€์„ ์ดˆ๋ž˜ํ•ฉ๋‹ˆ๋‹ค.
    • ๊ฐœ์„  ์ œ์•ˆ: Zustand๋กœ ์ƒํƒœ ๊ด€๋ฆฌ๋ฅผ ์ผ์›ํ™”ํ•˜๊ณ , ์‚ฌ์šฉ๋˜์ง€ ์•Š๋Š” Redux Toolkit ๊ด€๋ จ ํŒŒ์ผ๋“ค์„ ๋ชจ๋‘ ์ œ๊ฑฐํ•˜๋Š” ๊ฒƒ์„ ๊ฐ•๋ ฅํžˆ ๊ถŒ์žฅํ•ฉ๋‹ˆ๋‹ค. ํ˜„์žฌ ์ฝ”๋“œ ๊ตฌ์กฐ์™€ UI ์ปดํฌ๋„ŒํŠธ์˜ ์‚ฌ์šฉ ํŒจํ„ด์„ ๋ณผ ๋•Œ Zustand๋ฅผ ์ฃผ๋ ฅ์œผ๋กœ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์˜๋„๋œ ๊ฒƒ์œผ๋กœ ํŒ๋‹จ๋ฉ๋‹ˆ๋‹ค.
      • ์ œ๊ฑฐ ๋Œ€์ƒ ํŒŒ์ผ:
        • src/slices/cartSlice.ts
        • src/slices/modalSlice.ts
        • src/store/store.ts
        • src/hooks/useCustomRedux.ts (์ด ํŒŒ์ผ์€ Redux ํ›…์„ ๋ž˜ํ•‘ํ•˜๋Š” ์šฉ๋„์ด๋ฏ€๋กœ, Redux ์ œ๊ฑฐ ์‹œ ํ•จ๊ป˜ ์ œ๊ฑฐ๋˜์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.)
    • ๊ธฐ๋Œ€ ํšจ๊ณผ: ์ฝ”๋“œ๋ฒ ์ด์Šค ๋‹จ์ˆœํ™”, ์œ ์ง€๋ณด์ˆ˜์„ฑ ํ–ฅ์ƒ, ๋ถˆํ•„์š”ํ•œ ํ•™์Šต ๊ณก์„  ์ œ๊ฑฐ.
  2. ํƒ€์ž… ์ •์˜ ์ค‘์•™ํ™” ๋ฐ price ํƒ€์ž… ๊ฐœ์„ 

    • ๋ฌธ์ œ์ : CartItemType ์ธํ„ฐํŽ˜์ด์Šค๊ฐ€ src/constants/cartItems.ts, src/store/useCartStore.ts, src/types/cart.ts ์„ธ ๊ณณ์— ์ค‘๋ณต ์ •์˜๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค. ๋˜ํ•œ, CartItemType์˜ price ํ•„๋“œ๊ฐ€ string์œผ๋กœ ๋˜์–ด ์žˆ์–ด, ์ˆซ์ž ๊ณ„์‚ฐ์ด ํ•„์š”ํ•œ ๊ณณ์—์„œ parseInt()๋ฅผ ๋ฐ˜๋ณต์ ์œผ๋กœ ์‚ฌ์šฉํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
    • ๊ฐœ์„  ์ œ์•ˆ:
      1. src/types/cart.ts ํŒŒ์ผ์—์„œ CartItemType ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์œ ์ผํ•˜๊ฒŒ ์ •์˜ํ•˜๊ณ  exportํ•ฉ๋‹ˆ๋‹ค.
      2. CartItemType ๋‚ด price: string;์„ price: number; ๋กœ ๋ณ€๊ฒฝํ•ฉ๋‹ˆ๋‹ค.
      3. src/constants/cartItems.ts, src/store/useCartStore.ts, src/components/CartItem.tsx ๋“ฑ CartItemType์„ ์‚ฌ์šฉํ•˜๋Š” ๋ชจ๋“  ํŒŒ์ผ์—์„œ src/types/cart.ts๋กœ๋ถ€ํ„ฐ CartItemType์„ importํ•ด์„œ ์‚ฌ์šฉํ•˜๋„๋ก ์ˆ˜์ •ํ•ฉ๋‹ˆ๋‹ค.
      4. src/constants/cartItems.ts: cartItems ๋ฐฐ์—ด์˜ price ๊ฐ’์„ string ๋Œ€์‹  number๋กœ ์ง์ ‘ ์ž…๋ ฅํ•ฉ๋‹ˆ๋‹ค (์˜ˆ: "25000" -> 25000).
      5. src/components/CartItem.tsx: parseInt(price).toLocaleString()์„ price.toLocaleString()์œผ๋กœ ์ˆ˜์ •ํ•ฉ๋‹ˆ๋‹ค.
    • ๊ธฐ๋Œ€ ํšจ๊ณผ: ํƒ€์ž… ์ •์˜์˜ ์ผ๊ด€์„ฑ ์œ ์ง€, ํƒ€์ž… ์•ˆ์ •์„ฑ ๊ฐ•ํ™”, ๋ถˆํ•„์š”ํ•œ ๋Ÿฐํƒ€์ž„ parseInt ํ˜ธ์ถœ ์ œ๊ฑฐ (์„ฑ๋Šฅ ์†Œํญ ๊ฐœ์„ ), ์ฝ”๋“œ ๋ช…ํ™•์„ฑ ์ฆ๋Œ€.

[ํŒŒ์ผ๋ณ„ ์ฝ”๋“œ ๋ฆฌ๋ทฐ ๋ฐ ๊ฐœ์„  ์ œ์•ˆ]

1. src/App.tsx

  • ํŠน๋ณ„ํ•œ ๋ฌธ์ œ ์—†์ด ์ปดํฌ๋„ŒํŠธ ์กฐํ•ฉ์ด ์ž˜ ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค.

2. src/components/CartItem.tsx

  • ๋ถˆํ•„์š”ํ•œ import ์ œ๊ฑฐ ๋ฐ ์•„์ด์ฝ˜ ์ปดํฌ๋„ŒํŠธ ์‚ฌ์šฉ: ChevronUp, ChevronDown ์•„์ด์ฝ˜์ด import ๋˜์–ด ์žˆ์ง€๋งŒ ์‹ค์ œ๋กœ๋Š” ์ธ๋ผ์ธ SVG๊ฐ€ ์‚ฌ์šฉ๋˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. src/icons.tsx์—์„œ ์ •์˜๋œ ์ปดํฌ๋„ŒํŠธ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ถˆํ•„์š”ํ•œ import๋ฅผ ์ œ๊ฑฐํ•˜๊ณ  ์ฝ”๋“œ์˜ ์žฌ์‚ฌ์šฉ์„ฑ์„ ๋†’์—ฌ์ฃผ์„ธ์š”.
  • decrease ๋กœ์ง ์ค‘๋ณต ์ œ๊ฑฐ: ์ˆ˜๋Ÿ‰ ๊ฐ์†Œ ๋ฒ„ํŠผ(decrease) ํด๋ฆญ ์‹œ amount === 1์ผ ๋•Œ removeItem์„ ํ˜ธ์ถœํ•˜๋Š” ๋กœ์ง์ด ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ๋กœ์ง์€ Zustand ์Šคํ† ์–ด์˜ decrease ์•ก์…˜ ๋‚ด๋ถ€์—์„œ๋„ ์ฒ˜๋ฆฌ๋  ์ˆ˜ ์žˆ๋„๋ก ์„ค๊ณ„๋˜์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. UI ์ปดํฌ๋„ŒํŠธ์—์„œ๋Š” ๋‹จ์ˆœํžˆ dispatch(decrease(id)) (๋˜๋Š” useCartStore์˜ decrease(id))๋งŒ ํ˜ธ์ถœํ•˜๋„๋ก ์ˆ˜์ •ํ•˜์—ฌ ๊ด€์‹ฌ์‚ฌ๋ฅผ ๋ถ„๋ฆฌํ•ฉ๋‹ˆ๋‹ค.

3. src/components/CartList.tsx

  • ๋นˆ ์žฅ๋ฐ”๊ตฌ๋‹ˆ ํ™•์ธ ๋กœ์ง ๊ฐœ์„ : amount < 1 ๋Œ€์‹  cartItems.length === 0์„ ์‚ฌ์šฉํ•˜์—ฌ ์žฅ๋ฐ”๊ตฌ๋‹ˆ๊ฐ€ ๋น„์—ˆ๋Š”์ง€ ํ™•์ธํ•˜๋Š” ๊ฒƒ์ด ๋” ๋ช…ํ™•ํ•˜๊ณ  ์›๋ณธ ๋ฐ์ดํ„ฐ์— ๊ธฐ๋ฐ˜ํ•œ ์ผ๊ด€์„ฑ ์žˆ๋Š” ๋ฐฉ๋ฒ•์ž…๋‹ˆ๋‹ค.
  • calculateTotals ํ˜ธ์ถœ ๋นˆ๋„: useEffect์—์„œ cartItems๊ฐ€ ๋ณ€๊ฒฝ๋  ๋•Œ๋งˆ๋‹ค dispatch(calculateTotals())๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ๊ฒƒ์€ cartItems์˜ ์–‘์ด ๋งŽ์•„์งˆ ๊ฒฝ์šฐ ๋ฏธ๋ฏธํ•œ ์˜ค๋ฒ„ํ—ค๋“œ๋ฅผ ์œ ๋ฐœํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. Zustand ์Šคํ† ์–ด ๋‚ด์—์„œ amount์™€ total์„ ํŒŒ์ƒ ์ƒํƒœ(selector ๋˜๋Š” getter)๋กœ ๊ด€๋ฆฌํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ๊ณ ๋ คํ•˜๋ฉด ์ด useEffect๋ฅผ ์ œ๊ฑฐํ•˜๊ณ  ์ฝ”๋“œ๋ฅผ ๋” ๊ฐ„๊ฒฐํ•˜๊ฒŒ ๋งŒ๋“ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. (์•„๋ž˜ useCartStore.ts ๊ฐœ์„  ์ œ์•ˆ ์ฐธ๊ณ )

4. src/components/Modal.tsx

  • ๋ฒ„ํŠผ ํ…์ŠคํŠธ ์ƒ‰์ƒ ์ˆ˜์ •: "๋„ค" ๋ฒ„ํŠผ (clearCart๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ๋ฒ„ํŠผ)์˜ ํ…์ŠคํŠธ ์ƒ‰์ƒ (text-gray-700)์ด ๋ฐฐ๊ฒฝ์ƒ‰ (bg-red-500)๊ณผ ์–ด์šธ๋ฆฌ์ง€ ์•Š์•„ ๊ฐ€๋…์„ฑ์ด ๋–จ์–ด์ง‘๋‹ˆ๋‹ค. text-white๋กœ ๋ณ€๊ฒฝํ•˜์—ฌ ๊ฐ€๋…์„ฑ์„ ๋†’์ด๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค.
  • ๋ชจ๋‹ฌ ์ƒํƒœ ๋ถ„๋ฆฌ: Modal ์ปดํฌ๋„ŒํŠธ๋Š” useCartStore์—์„œ isOpen, openModal, closeModal ์ƒํƒœ/์•ก์…˜์„ ๊ฐ€์ ธ์˜ค๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ๋ชจ๋‹ฌ ๊ด€๋ จ ์ƒํƒœ๋Š” ์žฅ๋ฐ”๊ตฌ๋‹ˆ ์ƒํƒœ์™€ ์ง์ ‘์ ์ธ ๊ด€๋ จ์ด ์—†์œผ๋ฏ€๋กœ, ๋ณ„๋„์˜ useModalStore.ts๋กœ ๋ถ„๋ฆฌํ•˜์—ฌ ๊ด€๋ฆฌํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค.

5. src/components/Navbar.tsx

  • ๋ถˆํ•„์š”ํ•œ import ์ œ๊ฑฐ ๋ฐ ์•„์ด์ฝ˜ ์ปดํฌ๋„ŒํŠธ ์‚ฌ์šฉ: CartIcon์ด import ๋˜์–ด ์žˆ์ง€๋งŒ ์‹ค์ œ๋กœ๋Š” ์ธ๋ผ์ธ SVG๊ฐ€ ์‚ฌ์šฉ๋˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. src/icons.tsx์—์„œ ์ •์˜๋œ CartIcon ์ปดํฌ๋„ŒํŠธ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ถˆํ•„์š”ํ•œ import๋ฅผ ์ œ๊ฑฐํ•˜๊ณ  ์ฝ”๋“œ์˜ ์žฌ์‚ฌ์šฉ์„ฑ์„ ๋†’์—ฌ์ฃผ์„ธ์š”.

6. src/components/PriceBox.tsx

  • ํ˜„์žฌ ๋น„์–ด ์žˆ๋Š” ํŒŒ์ผ์ž…๋‹ˆ๋‹ค. ํ”„๋กœ์ ํŠธ์—์„œ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š”๋‹ค๋ฉด ์‚ญ์ œํ•˜์—ฌ ์ฝ”๋“œ ๋ฒ ์ด์Šค๋ฅผ ๊น”๋”ํ•˜๊ฒŒ ์œ ์ง€ํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค. ๋งŒ์•ฝ ์ถ”ํ›„ ์‚ฌ์šฉ๋  ์˜ˆ์ •์ด๋ผ๋ฉด, ํŒŒ์ผ ๋‚ด๋ถ€์— ์ฃผ์„์œผ๋กœ ํ•ด๋‹น ์ปดํฌ๋„ŒํŠธ์˜ ๋ชฉ์ ์„ ๋ช…์‹œํ•ด์ฃผ์„ธ์š”.

7. src/constants/cartItems.ts

  • CartItemType ์ œ๊ฑฐ ๋ฐ price ํƒ€์ž… ๋ณ€๊ฒฝ: ์œ„ "๊ฐ€์žฅ ์ค‘์š”ํ•œ ๊ฐœ์„  ์ œ์•ˆ 2๋ฒˆ"์— ๋”ฐ๋ผ CartItemType ์ธํ„ฐํŽ˜์ด์Šค ์ •์˜๋ฅผ ์ œ๊ฑฐํ•˜๊ณ  src/types/cart.ts์—์„œ importํ•˜์—ฌ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. price ํ•„๋“œ ๊ฐ’๋„ string์—์„œ number๋กœ ๋ณ€๊ฒฝํ•ฉ๋‹ˆ๋‹ค.

8. src/icons.tsx

  • ์•„์ด์ฝ˜ ์ปดํฌ๋„ŒํŠธ์˜ ์ค‘๋ณต ์ฝ”๋“œ ์ œ๊ฑฐ: ๊ฐ SVG ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋™์ผํ•œ SVG ์†์„ฑ(xmlns, fill, viewBox, strokeWidth, stroke)์„ ๋ฐ˜๋ณตํ•ด์„œ ์ •์˜ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ๊ณตํ†ต ์†์„ฑ์„ ๊ฐ์‹ธ๋Š” ํ—ฌํผ ํ•จ์ˆ˜๋‚˜ HOC(Higher-Order Component)๋ฅผ ๋งŒ๋“ค์–ด ์ค‘๋ณต์„ ์ œ๊ฑฐํ•˜๊ณ  ๋” ๊ฐ„๊ฒฐํ•˜๊ฒŒ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
    • ์˜ˆ์‹œ:
      // src/icons.tsx (๊ฐœ์„  ์˜ˆ์‹œ)
      import React from 'react';
      interface IconProps extends React.SVGProps<SVGSVGElement> { className?: string; }
      const createIcon = (pathData: string, defaultStrokeWidth: number = 1.5) => {
        return ({ className = "", ...props }: IconProps) => (
          <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"
               strokeWidth={defaultStrokeWidth} stroke="currentColor" className={className} {...props}>
            <path strokeLinecap="round" strokeLinejoin="round" d={pathData} />
          </svg>
        );
      };
      export const CartIcon = createIcon(
        "M2.25 3h1.386c.51 0 .955.343 1.087.835l.383 1.437M7.5 14.25a3 3 0 00-3 3h15.75m-12.75-3h11.218c1.121-2.3 2.1-4.684 2.924-7.138a60.114 60.114 0 00-16.536-1.84M7.5 14.25L5.106 5.272M6 20.25a.75.75 0 11-1.5 0 .75.75 0 011.5 0zm12.75 0a.75.75 0 11-1.5 0 .75.75 0 011.5 0z",
        1.5 // ์นดํŠธ ์•„์ด์ฝ˜์˜ strokeWidth
      );
      export const ChevronUp = createIcon("M4.5 15.75l7.5-7.5 7.5 7.5", 2);
      export const ChevronDown = createIcon("M19.5 8.25l-7.5 7.5-7.5-7.5", 2);

9. src/store/useCartStore.ts (Zustand Store)

  • CartItemType ์ œ๊ฑฐ ๋ฐ price ํƒ€์ž… ๋ณ€๊ฒฝ: ์œ„ "๊ฐ€์žฅ ์ค‘์š”ํ•œ ๊ฐœ์„  ์ œ์•ˆ 2๋ฒˆ"์— ๋”ฐ๋ผ CartItemType ์ธํ„ฐํŽ˜์ด์Šค ์ •์˜๋ฅผ ์ œ๊ฑฐํ•˜๊ณ  src/types/cart.ts์—์„œ importํ•˜์—ฌ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.
  • ์Šคํ† ์–ด ์ฑ…์ž„ ๋ถ„๋ฆฌ: CartState ์ธํ„ฐํŽ˜์ด์Šค์— ์žฅ๋ฐ”๊ตฌ๋‹ˆ์™€ ์ง์ ‘์ ์ธ ๊ด€๋ จ์ด ์—†๋Š” isOpen (๋ชจ๋‹ฌ ์ƒํƒœ)์ด ํฌํ•จ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋Š” ์Šคํ† ์–ด์˜ ๊ด€์‹ฌ์‚ฌ ๋ถ„๋ฆฌ๋ฅผ ์•ฝํ™”์‹œํ‚ค๋ฏ€๋กœ, ๋ชจ๋‹ฌ ๊ด€๋ จ ์ƒํƒœ(isOpen)์™€ ์•ก์…˜(openModal, closeModal)์„ ๋ณ„๋„์˜ src/store/useModalStore.ts ํŒŒ์ผ๋กœ ๋ถ„๋ฆฌํ•ฉ๋‹ˆ๋‹ค.
  • ํŒŒ์ƒ ์ƒํƒœ (amount, total) ๊ด€๋ฆฌ ๊ฐœ์„ : amount์™€ total์€ cartItems ๋ฐฐ์—ด์—์„œ ํŒŒ์ƒ๋˜๋Š” ๊ฐ’์ž…๋‹ˆ๋‹ค. calculateTotals ์•ก์…˜์„ ํ†ตํ•ด ๋ช…์‹œ์ ์œผ๋กœ ๊ณ„์‚ฐํ•˜๊ณ  set์œผ๋กœ ์—…๋ฐ์ดํŠธํ•˜๋Š” ๋Œ€์‹ , Zustand์˜ selectors๋ฅผ ํ™œ์šฉํ•˜๊ฑฐ๋‚˜ ์Šคํ† ์–ด ์ž์ฒด์— getter ๋กœ์ง์„ ์ถ”๊ฐ€ํ•˜์—ฌ ์ปดํฌ๋„ŒํŠธ์—์„œ ์ง์ ‘ ๊ณ„์‚ฐํ•˜๋„๋ก ํ•˜๋Š” ๊ฒƒ์ด ๋” ํšจ์œจ์ ์ด๊ณ  ๊ฐ„๊ฒฐํ•ฉ๋‹ˆ๋‹ค. ์ด ๋ฐฉ์‹์„ ์ ์šฉํ•˜๋ฉด calculateTotals ์•ก์…˜๊ณผ CartList.tsx์˜ useEffect๋ฅผ ์ œ๊ฑฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
    • ์˜ˆ์‹œ:
      // src/store/useCartStore.ts (๊ฐœ์„  ์˜ˆ์‹œ)
      import { create } from "zustand";
      import { CartItemType } from "../types/cart"; // ์ค‘์•™ํ™”๋œ ํƒ€์ž…์—์„œ import
      
      interface CartState {
        cartItems: CartItemType[];
        // amount, total์€ getter ๋˜๋Š” selector๋กœ ์ฒ˜๋ฆฌํ•˜๋ฏ€๋กœ ์ง์ ‘ ์ƒํƒœ์— ํฌํ•จ์‹œํ‚ค์ง€ ์•Š์„ ์ˆ˜ ์žˆ์Œ
      }
      
      interface CartActions {
        // ... (๊ธฐ์กด ์•ก์…˜๋“ค) ...
        get total(): number; // Getter๋กœ ์ถ”๊ฐ€
        get amount(): number; // Getter๋กœ ์ถ”๊ฐ€
      }
      
      export const useCartStore = create<CartState & CartActions>((set, get) => ({
        cartItems: [/* ์ดˆ๊ธฐ ๋ฐ์ดํ„ฐ */],
        // ... (๊ธฐ์กด ์•ก์…˜๋“ค) ...
      
        // Getter ๊ตฌํ˜„
        get total() {
          return get().cartItems.reduce((acc, item) => acc + item.amount * item.price, 0);
        },
        get amount() {
          return get().cartItems.reduce((acc, item) => acc + item.amount, 0);
        },
      
        // decrease ์•ก์…˜์—์„œ removeItem ์žฌํ™œ์šฉ
        decrease: (id) =>
          set((state) => {
            const itemToCheck = state.cartItems.find((item) => item.id === id);
            if (itemToCheck && itemToCheck.amount <= 1) { // 0์ดํ•˜๋กœ ๋–จ์–ด์ง€๋Š” ๊ฒฝ์šฐ๋„ ํฌํ•จ
              // ์ˆ˜๋Ÿ‰์ด 1์ดํ•˜๊ฐ€ ๋˜๋ฉด ํ•ด๋‹น ์•„์ดํ…œ ์ œ๊ฑฐ
              return {
                cartItems: state.cartItems.filter((item) => item.id !== id),
              };
            }
            // ๊ทธ ์™ธ์—” ๊ฐ์†Œ
            const newCartItems = state.cartItems.map((item) =>
              item.id === id ? { ...item, amount: item.amount - 1 } : item
            );
            return { cartItems: newCartItems };
          }),
      }));
  • decrease ๋กœ์ง ๋ฆฌํŒฉํ† ๋ง: decrease ์•ก์…˜ ๋‚ด์—์„œ ์•„์ดํ…œ ์ˆ˜๋Ÿ‰์ด 1 ๋ฏธ๋งŒ์ผ ๋•Œ filter๋ฅผ ํ†ตํ•ด ์•„์ดํ…œ์„ ์ œ๊ฑฐํ•˜๋Š” ๋กœ์ง์€ removeItem ์•ก์…˜๊ณผ ์œ ์‚ฌํ•ฉ๋‹ˆ๋‹ค. decrease ์•ก์…˜ ๋‚ด์—์„œ ์ˆ˜๋Ÿ‰์ด 1 ๋ฏธ๋งŒ์œผ๋กœ ๋–จ์–ด์งˆ ๊ฒฝ์šฐ, ํ•ด๋‹น ์•„์ดํ…œ์„ filter๋กœ ์ง์ ‘ ์ œ๊ฑฐํ•˜๊ฑฐ๋‚˜ removeItem ์•ก์…˜์„ ํ˜ธ์ถœํ•˜๋„๋ก ๋กœ์ง์„ ์ˆ˜์ •ํ•˜์—ฌ ์ค‘๋ณต์„ ํ”ผํ•˜๊ณ  ์˜๋„๋ฅผ ๋ช…ํ™•ํžˆ ํ•ฉ๋‹ˆ๋‹ค.

10. src/types/modal.ts

  • useModalStore๋ฅผ ๋ถ„๋ฆฌํ•  ๊ฒฝ์šฐ, ์ด ํŒŒ์ผ์—์„œ ๋ชจ๋‹ฌ ๊ด€๋ จ ํƒ€์ž…์„ ์ •์˜ํ•˜๋„๋ก ๊ตฌ์กฐ๋ฅผ ๊ฐœ์„ ํ•ฉ๋‹ˆ๋‹ค.

11. src/main.tsx

  • React.StrictMode๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๊ฐœ๋ฐœ ๋‹จ๊ณ„์—์„œ ์ž ์žฌ์  ๋ฌธ์ œ๋ฅผ ๊ฐ์ง€ํ•˜๋Š” ๊ฒƒ์€ ์ข‹์€ ์ ‘๊ทผ์ž…๋‹ˆ๋‹ค. Zustand๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ Provider ์ปดํฌ๋„ŒํŠธ๋Š” ํ•„์š”ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

12. src/vite-env.d.ts

  • ํŠน๋ณ„ํ•œ ๋ฌธ์ œ ์—†์Šต๋‹ˆ๋‹ค.

[ํ”„๋กœ์ ํŠธ ์„ค์ • ๋ฐ ์˜์กด์„ฑ ๋ฆฌ๋ทฐ]

1. ESLint ์„ค์ • (.eslintrc.cjs)

  • ESLint ํƒ€์ž… ๊ธฐ๋ฐ˜ ๊ทœ์น™ ํ™œ์„ฑํ™” (ํ•„์ˆ˜): ํ˜„์žฌ @typescript-eslint/recommended๋ฅผ ์‚ฌ์šฉํ•˜์ง€๋งŒ, ๋” ๊ฐ•๋ ฅํ•œ ํƒ€์ž… ๊ธฐ๋ฐ˜ ๋ฆฐํŒ… ๊ทœ์น™(recommended-type-checked ๋˜๋Š” strict-type-checked)์„ ํ™œ์„ฑํ™”ํ•˜๋„๋ก ๊ถŒ์žฅํ•ฉ๋‹ˆ๋‹ค. parserOptions.project ์„ค์ • ๋ฐ extends ๋ฐฐ์—ด์— plugin:@typescript-eslint/recommended-type-checked๋ฅผ ์ถ”๊ฐ€ํ•˜์—ฌ TypeScript ์ฝ”๋“œ์— ๋Œ€ํ•œ ์ •์  ๋ถ„์„์„ ๊ฐ•ํ™”ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
  • ESLint ๋ฒ„์ „ ์—…๋ฐ์ดํŠธ (์ตœ์‹ ํ™”): package-lock.json์— [email protected] ๋ฒ„์ „์ด "This version is no longer supported."๋ผ๊ณ  ๋ช…์‹œ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค. ESLint๋ฅผ ์ตœ์‹  LTS ๋ฒ„์ „์ธ ^9.0.0 (๋˜๋Š” ์ตœ์‹  ์•ˆ์ • ๋ฒ„์ „)์œผ๋กœ ์—…๋ฐ์ดํŠธํ•˜์—ฌ ์ตœ์‹  ๊ธฐ๋Šฅ ๋ฐ ๋ฒ„๊ทธ ์ˆ˜์ •์„ ํ™œ์šฉํ•˜๊ณ  ์ง€์›์ด ์ค‘๋‹จ๋œ ๋ฒ„์ „์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋„๋ก ํ•ด์ฃผ์„ธ์š”. ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ๊ฐ€์ด๋“œ๋ฅผ ์ฐธ๊ณ ํ•˜์—ฌ ์„ค์ • ํŒŒ์ผ ๋ณ€๊ฒฝ์ด ํ•„์š”ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ESLint React ํ”Œ๋Ÿฌ๊ทธ์ธ ์ถ”๊ฐ€ (React ๊ถŒ์žฅ์‚ฌํ•ญ): eslint-plugin-react๋ฅผ ์„ค์น˜ํ•˜๊ณ  .eslintrc.cjs์˜ extends์— plugin:react/recommended ๋ฐ plugin:react/jsx-runtime์„ ์ถ”๊ฐ€ํ•˜์—ฌ React ๊ด€๋ จ ์ฝ”๋“œ์— ๋Œ€ํ•œ ๋ฆฐํŒ… ๊ทœ์น™์„ ๊ฐ•ํ™”ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
  • react-refresh/only-export-components ๊ทœ์น™ ๊ฒ€ํ† : allowConstantExport: true ์˜ต์…˜์€ Hot Module Replacement (HMR)์—์„œ ์ž ์žฌ์  ๋ฌธ์ œ๋ฅผ ์ผ์œผํ‚ฌ ์ˆ˜ ์žˆ๋Š” edge case๋ฅผ ํ—ˆ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. Fast Refresh ๋™์ž‘์— ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•˜๊ฑฐ๋‚˜ ๋” ์—„๊ฒฉํ•œ HMR ๊ทœ์น™์„ ์ ์šฉํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด ์ด ์˜ต์…˜์„ false๋กœ ์„ค์ •ํ•˜๊ณ  ์ปดํฌ๋„ŒํŠธ ๋‚ด๋ณด๋‚ด๊ธฐ ๋ฐฉ์‹์„ ์žฌ๊ฒ€ํ† ํ•˜๋Š” ๊ฒƒ์„ ๊ณ ๋ คํ•ด๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ignorePatterns ์ •๋ฆฌ: .eslintrc.cjs ํŒŒ์ผ์ด ignorePatterns ๋ชฉ๋ก์— ์ž๊ธฐ ์ž์‹ ์„ ํฌํ•จํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ๋ณดํ†ต ๋ฆฐํ„ฐ๋Š” ์„ค์ • ํŒŒ์ผ์„ ๋ฆฐํŒ…ํ•˜์ง€ ์•Š์œผ๋ฏ€๋กœ, ์ด ํŒจํ„ด์€ ๋ถˆํ•„์š”ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

2. ์˜์กด์„ฑ ๊ด€๋ฆฌ (package-lock.json)

  • ์˜์กด์„ฑ ๋ฉ”์ด์ € ๋ฒ„์ „ ์—…๋ฐ์ดํŠธ ํ™•์ธ ๋ฐ ํ…Œ์ŠคํŠธ ๊ฐ•ํ™”: @reduxjs/toolkit, esbuild, @tailwindcss/* ๋“ฑ ์—ฌ๋Ÿฌ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋“ค์ด ์—…๋ฐ์ดํŠธ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ๋ฉ”์ด์ € ๋ฒ„์ „ ์—…๋ฐ์ดํŠธ๋Š” ์ž ์žฌ์ ์ธ breaking change๋ฅผ ํฌํ•จํ•  ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ, ๋ฆด๋ฆฌ์Šค ๋…ธํŠธ๋ฅผ ๋ฉด๋ฐ€ํžˆ ๊ฒ€ํ† ํ•˜๊ณ  ์ถฉ๋ถ„ํ•œ ํ…Œ์ŠคํŠธ๋ฅผ ์ˆ˜ํ–‰ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
  • Deprecated ์˜์กด์„ฑ ์ฒ˜๋ฆฌ: eslint (8.57.1)์™€ @humanwhocodes/config-array (0.13.0) ํŒจํ‚ค์ง€์— deprecated ๊ฒฝ๊ณ ๊ฐ€ ๋ถ™์–ด ์žˆ์Šต๋‹ˆ๋‹ค. Deprecated ๋œ ์˜์กด์„ฑ์€ ๋ณด์•ˆ ์ทจ์•ฝ์ , ๋ฒ„๊ทธ ์ˆ˜์ • ๋ฏธ๋ฐ˜์˜, ํ˜ธํ™˜์„ฑ ๋ฌธ์ œ์˜ ์›์ธ์ด ๋  ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ, ๊ฐ€๋Šฅํ•œ ํ•œ ๋นจ๋ฆฌ ์ง€์›๋˜๋Š” ์ตœ์‹  ๋ฒ„์ „์œผ๋กœ ์—…๋ฐ์ดํŠธํ•˜๊ฑฐ๋‚˜ ๋Œ€์ฒด ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ๊ฒ€ํ† ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
  • ๋ฒˆ๋“ค ์‚ฌ์ด์ฆˆ ๋ณ€ํ™” ๋ชจ๋‹ˆํ„ฐ๋ง: ๋นŒ๋“œ ๋ฐ ์Šคํƒ€์ผ๋ง ๊ด€๋ จ ์˜์กด์„ฑ๋“ค์ด ๋Œ€๊ฑฐ ์ถ”๊ฐ€๋˜๊ฑฐ๋‚˜ ์—…๋ฐ์ดํŠธ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ๋ฒˆ๋“ค ๋ถ„์„ ๋„๊ตฌ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ตœ์ข… ๋นŒ๋“œ ๋ฒˆ๋“ค ํฌ๊ธฐ์— ์–ด๋–ค ๋ณ€ํ™”๊ฐ€ ์žˆ์—ˆ๋Š”์ง€ ๋ถ„์„ํ•˜๊ณ  ์ตœ์ ํ™” ํฌ์ธํŠธ๋ฅผ ์ฐพ์•„๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • Node.js ์—”์ง„ ํ˜ธํ™˜์„ฑ ํ™•์ธ: ํ”„๋กœ์ ํŠธ๊ฐ€ ์‚ฌ์šฉํ•˜๋Š” Node.js ๋ฒ„์ „์ด ๋ชจ๋“  ์ƒˆ๋กœ ์—…๋ฐ์ดํŠธ๋˜๊ฑฐ๋‚˜ ์ถ”๊ฐ€๋œ ์˜์กด์„ฑ๋“ค์˜ engines.node ์š”๊ตฌ์‚ฌํ•ญ์„ ๋งŒ์กฑํ•˜๋Š”์ง€ ํ™•์ธํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
  • dev ์˜์กด์„ฑ ๋ช…ํ™•ํ™” ๋ฐ ๊ฒ€์ฆ: dev: true๋กœ ํ‘œ์‹œ๋œ ์˜์กด์„ฑ๋“ค์ด ์‹ค์ œ๋กœ ๊ฐœ๋ฐœ ๋ฐ ๋นŒ๋“œ ๊ณผ์ •์—์„œ๋งŒ ์‚ฌ์šฉ๋˜๊ณ  ๋Ÿฐํƒ€์ž„ ๋ฒˆ๋“ค์— ํฌํ•จ๋˜์ง€ ์•Š๋„๋ก ๋นŒ๋“œ ์„ค์ •์„ ๊ฒ€์ฆํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
  • ๋ณด์•ˆ ์ทจ์•ฝ์  ์Šค์บ” ์ž๋™ํ™”: npm audit ๋˜๋Š” yarn audit ๋ช…๋ น์–ด๋ฅผ CI/CD ํŒŒ์ดํ”„๋ผ์ธ์— ํฌํ•จ์‹œ์ผœ Pull Request๊ฐ€ ๋จธ์ง€๋˜๊ธฐ ์ „์— ์ž๋™์œผ๋กœ ๋ณด์•ˆ ์ทจ์•ฝ์ ์„ ๊ฒ€์‚ฌํ•˜๋„๋ก ์„ค์ •ํ•˜๋Š” ๊ฒƒ์„ ๊ถŒ์žฅํ•ฉ๋‹ˆ๋‹ค.

3. ๋ฌธ์„œํ™” (README.md)

  • ์ดˆ๊ธฐ ๋‚ด์šฉ ๋ณด๊ฐ•: ํ˜„์žฌ README.md๋Š” Vite ํ”„๋กœ์ ํŠธ ์ƒ์„ฑ ์‹œ์˜ ๊ธฐ๋ณธ ์„ค๋ช…๋งŒ์„ ํฌํ•จํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ํ”„๋กœ์ ํŠธ์˜ ๋ชฉ์ , ์ฃผ์š” ๊ธฐ๋Šฅ, ๊ฐœ๋ฐœ ํ™˜๊ฒฝ ์„ค์ • ๋ฐฉ๋ฒ•, ๋นŒ๋“œ ๋ฐ ๋ฐฐํฌ ๋ฐฉ๋ฒ•, ๊ทธ๋ฆฌ๊ณ  ์Šคํฌ๋ฆฝํŠธ(package.json์˜ scripts ์„น์…˜)์— ๋Œ€ํ•œ ๊ฐ„๋žตํ•œ ์„ค๋ช…์„ ์ถ”๊ฐ€ํ•˜์—ฌ ํ”„๋กœ์ ํŠธ ์ดํ•ด๋„๋ฅผ ๋†’์—ฌ์ฃผ์„ธ์š”.

[์ „๋ฐ˜์ ์ธ ์ฝ”๋“œ ํ’ˆ์งˆ ๊ฐœ์„ ์ ]

  • ๋ณ€์ˆ˜๋ช…, ํ•จ์ˆ˜๋ช…, ์ฃผ์„ ํ’ˆ์งˆ: ์ „๋ฐ˜์ ์œผ๋กœ ๋ณ€์ˆ˜๋ช…, ํ•จ์ˆ˜๋ช…์€ ์˜๋ฏธ๊ฐ€ ๋ช…ํ™•ํ•˜๊ณ  ์ข‹์Šต๋‹ˆ๋‹ค. ์ฃผ์„์€ ํ˜„์žฌ ์ฝ”๋“œ๋ฅผ ์ดํ•ดํ•˜๋Š” ๋ฐ ๋„์›€์ด ๋˜์ง€๋งŒ, ํŠนํžˆ ์ปค์Šคํ…€ ํ›…์ด๋‚˜ ๋ณต์žกํ•œ ๋กœ์ง, ํ•ต์‹ฌ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์ด ํฌํ•จ๋œ ํŒŒ์ผ์—๋Š” JSDoc ํ˜•ํƒœ์˜ ์ฃผ์„์„ ์ถ”๊ฐ€ํ•˜์—ฌ ์ฝ”๋“œ ๋ฌธ์„œํ™”๋ฅผ ๊ฐ•ํ™”ํ•˜๋Š” ๊ฒƒ์„ ๊ถŒ์žฅํ•ฉ๋‹ˆ๋‹ค.
  • React ์ปดํฌ๋„ŒํŠธ ํƒ€์ž… ์ •์˜ ์ผ๊ด€์„ฑ: const Component = ({ prop }: Type) => {...} ํ˜•ํƒœ ๋Œ€์‹  const Component: React.FC<PropsType> = ({ prop }) => {...} ์™€ ๊ฐ™์ด React.FC๋ฅผ ๋ช…์‹œ์ ์œผ๋กœ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด React ์ปดํฌ๋„ŒํŠธ์ž„์„ ๋” ๋ช…ํ™•ํ•˜๊ฒŒ ๋ณด์—ฌ์ฃผ๊ณ , ์ถ”๊ฐ€์ ์ธ ํƒ€์ž… ์•ˆ์ „์„ฑ ์ด์ ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

๋งˆ์ง€๋ง‰์œผ๋กœ, ์ „๋ฐ˜์ ์œผ๋กœ ๊ธฐ๋Šฅ ๊ตฌํ˜„์€ ์ž˜ ๋˜์–ด ์žˆ์œผ๋‚˜, ์ƒํƒœ ๊ด€๋ฆฌ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์„ ํƒ์˜ ๋ชจํ˜ธ์„ฑ๊ณผ ํƒ€์ž… ์ •์˜์˜ ์ค‘๋ณต์ด ์ฃผ์š” ๊ฐœ์„ ์ ์œผ๋กœ ๋ณด์ž…๋‹ˆ๋‹ค. ์œ„์˜ ์ œ์•ˆ๋“ค์„ ํ†ตํ•ด ์ฝ”๋“œ์˜ ์ผ๊ด€์„ฑ, ๊ฐ€๋…์„ฑ, ์œ ์ง€๋ณด์ˆ˜์„ฑ, ๊ทธ๋ฆฌ๊ณ  ํƒ€์ž… ์•ˆ์ „์„ฑ์„ ํฌ๊ฒŒ ๋†’์ผ ์ˆ˜ ์žˆ์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๊ถ๊ธˆํ•œ ์ ์ด ์žˆ์œผ์‹œ๋ฉด ์–ธ์ œ๋“ ์ง€ ์งˆ๋ฌธํ•ด์ฃผ์„ธ์š”. ๊ฒ€ํ† ํ•ด ์ฃผ์…”์„œ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค!

@sueonnn sueonnn changed the title Create Week9 Mission1,2,3 Create Week9 Mission0,1,2,3 Dec 14, 2025
Copy link
Collaborator

@woojo230 woojo230 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

์ค‘๋ณต๋˜๋Š” ๋กœ์ง์€ ์œ ํ‹ธ ํ•จ์ˆ˜๋‚˜ ์ปดํฌ๋„ŒํŠธ๋กœ ๋ถ„๋ฆฌํ•˜๋ฉด ์ข‹์„ ๊ฒƒ ๊ฐ™์•„์š”

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants