Skip to content

Conversation

@dongyeol02
Copy link
Contributor

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

Week9 Mission0~3

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

-๋ฆฌ๋“€์Šคํˆดํ‚ท ๋ฐ zustand๋กœ ์Œ์› ์นดํŠธ ํŽ˜์ด์ง€ ๊ตฌ์„ฑ

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

2025-12-15.8.18.10.mov

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

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

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

@dongyeol02 dongyeol02 requested a review from woojo230 December 15, 2025 11:27
@dongyeol02 dongyeol02 self-assigned this Dec 15, 2025
@github-actions
Copy link

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

์•ˆ๋…•ํ•˜์„ธ์š”, ๋™๋ ฌ๋‹˜. ์‹œ๋‹ˆ์–ด ํ”„๋ก ํŠธ์—”๋“œ ๊ฐœ๋ฐœ์ž๋กœ์„œ ์ œ์ถœํ•ด์ฃผ์‹  Pull Request์˜ ๋ณ€๊ฒฝ ์‚ฌํ•ญ์„ ๋ฉด๋ฐ€ํžˆ ๊ฒ€ํ† ํ–ˆ์Šต๋‹ˆ๋‹ค.
์ด๋ฒˆ ๋ฆฌ๋ทฐ๋Š” src ๋””๋ ‰ํ† ๋ฆฌ ๋‚ด .ts ๋ฐ .tsx ํŒŒ์ผ๋“ค์„ ์ค‘์‹ฌ์œผ๋กœ, ํ”„๋กœ์ ํŠธ ์ „๋ฐ˜์˜ ์„ค์ • ํŒŒ์ผ๊ณผ ์ปดํฌ๋„ŒํŠธ, ์ƒํƒœ ๊ด€๋ฆฌ ๋กœ์ง์„ ํฌ๊ด„ํ•˜์—ฌ ์ง„ํ–‰ํ–ˆ์Šต๋‹ˆ๋‹ค.


PR ํ†ตํ•ฉ ๋ฆฌ๋ทฐ ์š”์•ฝ

์ „๋ฐ˜์ ์œผ๋กœ ๊ธฐ๋Šฅ ๊ตฌํ˜„์€ ์ž˜ ๋˜์–ด ์žˆ์œผ๋ฉฐ, Redux Toolkit๊ณผ Zustand ์‚ฌ์šฉ์— ๋Œ€ํ•œ ์ดํ•ด๊ฐ€ ๋‹๋ณด์ž…๋‹ˆ๋‹ค. ํŠนํžˆ UseReducerCompany.tsx์—์„œ reducer ๋‚ด ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ๋ฅผ ์ฒ˜๋ฆฌํ•˜์—ฌ ์ƒํƒœ๋ฅผ ์ œ์–ดํ•˜๋Š” ๋ฐฉ์‹์ด ์ธ์ƒ์ ์ž…๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๋ช‡ ๊ฐ€์ง€ ์ค‘๋Œ€ํ•œ ๊ฐœ์„ ์ ์ด ๋ฐœ๊ฒฌ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ๊ฐ€์žฅ ํ•ต์‹ฌ์ ์ธ ๋ฌธ์ œ๋Š” Redux Toolkit๊ณผ Zustand ๋‘ ๊ฐ€์ง€ ์ƒํƒœ ๊ด€๋ฆฌ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ๋™์‹œ์—, ์‹ฌ์ง€์–ด ๋™์ผํ•œ ๊ด€์‹ฌ์‚ฌ(์žฅ๋ฐ”๊ตฌ๋‹ˆ, ๋ชจ๋‹ฌ)์— ๋Œ€ํ•ด ์‚ฌ์šฉํ•˜๊ณ  ์žˆ๋‹ค๋Š” ์ ์ž…๋‹ˆ๋‹ค. ์ด๋Š” ์ฝ”๋“œ์˜ ๋ณต์žก์„ฑ์„ ๊ฐ€์ค‘์‹œํ‚ค๊ณ  ์œ ์ง€๋ณด์ˆ˜๋ฅผ ์–ด๋ ต๊ฒŒ ํ•˜๋ฉฐ, ์ƒํƒœ์˜ ๋‹จ์ผ ์ง„์‹ค ๊ณต๊ธ‰์›์„ ํ›ผ์†ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด์™ธ์—๋„ TypeScript ํƒ€์ž… ์ •์˜์˜ ์ผ๊ด€์„ฑ, ์„ฑ๋Šฅ ์ตœ์ ํ™”, ์ฝ”๋“œ ํ’ˆ์งˆ ๋ฐ ์ ‘๊ทผ์„ฑ ์ธก๋ฉด์—์„œ ๊ฐœ์„ ํ•  ์ˆ˜ ์žˆ๋Š” ๋ถ€๋ถ„๋“ค์ด ์žˆ์Šต๋‹ˆ๋‹ค.


ํ”„๋กœ์ ํŠธ ์ „๋ฐ˜์˜ ๊ฐœ์„  ์ œ์•ˆ

.ts, .tsx ํŒŒ์ผ์˜ ํ’ˆ์งˆ์— ์ง์ ‘์ ์ธ ์˜ํ–ฅ์„ ๋ฏธ์น˜๋ฏ€๋กœ ๊ด€๋ จ๋œ ๊ฐœ์„  ์ œ์•ˆ์„ ๋“œ๋ฆฝ๋‹ˆ๋‹ค.

  1. TypeScript ESLint ์„ค์ • ๊ฐ•ํ™” (ํƒ€์ž… ๊ฐœ์„ ์ )

    • ํ˜„์žฌ tseslint.configs.recommended๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์ง€๋งŒ, tseslint.configs.recommendedTypeChecked ๋˜๋Š” tseslint.configs.strictTypeChecked๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํƒ€์ž… ์ •๋ณด๋ฅผ ํ™œ์šฉํ•˜๋Š” Lint ๊ทœ์น™์„ ์ ์šฉํ•˜๋ฉด ์ž ์žฌ์  ์˜ค๋ฅ˜๋ฅผ ๋”์šฑ ํšจ๊ณผ์ ์œผ๋กœ ๋ฐฉ์ง€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
    • ์ œ์•ˆ: eslint.config.js์—์„œ tseslint.configs.recommended๋ฅผ tseslint.configs.recommendedTypeChecked๋กœ ๋ณ€๊ฒฝํ•˜๊ณ , languageOptions.parserOptions.project ์„ค์ •์ด tsconfig.json์„ ์ •ํ™•ํžˆ ๊ฐ€๋ฆฌํ‚ค๋Š”์ง€ ํ™•์ธํ•˜์„ธ์š”.
  2. React ์ „์šฉ ESLint ํ”Œ๋Ÿฌ๊ทธ์ธ ์ถ”๊ฐ€ (์ฝ”๋“œ ํ’ˆ์งˆ)

    • eslint-plugin-react-x ๋ฐ eslint-plugin-react-dom์„ ์ถ”๊ฐ€ํ•˜์—ฌ React ์ปดํฌ๋„ŒํŠธ ์ž‘์„ฑ์— ๋Œ€ํ•œ ๊นŠ์ด ์žˆ๋Š” ๊ฐ€์ด๋“œ๋ผ์ธ์„ ์ œ๊ณตํ•˜๊ณ  ์ฝ”๋“œ ํ’ˆ์งˆ์„ ํ–ฅ์ƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
    • ์ œ์•ˆ: ํ•ด๋‹น ํ”Œ๋Ÿฌ๊ทธ์ธ์„ ์„ค์น˜ํ•˜๊ณ  eslint.config.js์˜ extends ๋ฐฐ์—ด์— reactX.configs['recommended-typescript']์™€ reactDom.configs.recommended๋ฅผ ์ถ”๊ฐ€ํ•˜์„ธ์š”.
  3. ecmaVersion ์„ค์ • ์—…๋ฐ์ดํŠธ (์ฝ”๋“œ ํ’ˆ์งˆ)

    • eslint.config.js์˜ languageOptions.ecmaVersion์ด 2020์œผ๋กœ ์„ค์ •๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค. ์ตœ์‹  JavaScript ๋ฌธ๋ฒ•์„ ์ •ํ™•ํžˆ ํŒŒ์‹ฑํ•˜๊ณ  ๋ฆฐํŒ…ํ•˜๊ธฐ ์œ„ํ•ด latest๋‚˜ 2023 ๋“ฑ์œผ๋กœ ์—…๋ฐ์ดํŠธํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค.
    • ์ œ์•ˆ: eslint.config.js์—์„œ ecmaVersion: 2020์„ ecmaVersion: 'latest' ๋˜๋Š” ecmaVersion: 2023์œผ๋กœ ๋ณ€๊ฒฝํ•˜์„ธ์š”.
  4. ์ ˆ๋Œ€ ๊ฒฝ๋กœ ์ž„ํฌํŠธ ์„ค์ • (๋ฆฌํŒฉํ† ๋ง ํฌ์ธํŠธ)

    • ํ˜„์žฌ ์ƒ๋Œ€ ๊ฒฝ๋กœ ์ž„ํฌํŠธ๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์–ด ํ”„๋กœ์ ํŠธ ๊ทœ๋ชจ๊ฐ€ ์ปค์ง€๋ฉด ๋ณต์žกํ•ด์งˆ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. tsconfig.json๊ณผ vite.config.ts์—์„œ ๊ฒฝ๋กœ ๋ณ„์นญ(path aliases)์„ ์„ค์ •ํ•˜๋ฉด ๋” ๊น”๋”ํ•˜๊ณ  ๊ด€๋ฆฌํ•˜๊ธฐ ์‰ฌ์šด ์ ˆ๋Œ€ ๊ฒฝ๋กœ ์ž„ํฌํŠธ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
    • ์ œ์•ˆ: tsconfig.json์— paths ์˜ต์…˜์„ ์„ค์ •ํ•˜๊ณ , vite.config.ts์—๋„ ํ•ด๋‹น alias๋ฅผ ์„ค์ •ํ•œ ํ›„ ์ž„ํฌํŠธ ๋ฌธ์„ ์—…๋ฐ์ดํŠธํ•˜์„ธ์š”.

ํŒŒ์ผ๋ณ„ ์ƒ์„ธ ํ”ผ๋“œ๋ฐฑ ๋ฐ ๊ฐœ์„  ์ œ์•ˆ

src/App.tsx

  • ํƒ€์ž… ๊ฐœ์„ ์ : App ์ปดํฌ๋„ŒํŠธ์˜ ๋ฐ˜ํ™˜ ํƒ€์ž…์„ ๋ช…์‹œ์ ์œผ๋กœ JSX.Element๋กœ ์ง€์ •ํ•˜์—ฌ ๊ฐ€๋…์„ฑ๊ณผ ๋ช…ํ™•์„ฑ์„ ๋†’์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. (function App(): JSX.Element { ๋˜๋Š” const App: React.FC = () => {).
  • ์ฝ”๋“œ ํ’ˆ์งˆ: ํ˜„์žฌ ์ค‘๋ณต ์ฝ”๋“œ๊ฐ€ ์—†์œผ๋ฉฐ ๊น”๋”ํ•˜๊ฒŒ ์ž‘์„ฑ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. <></> (Fragment) ์‚ฌ์šฉ๋„ ์ ์ ˆํ•ฉ๋‹ˆ๋‹ค.

src/main.tsx

  • ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ/๊ฐ•๊ฑด์„ฑ: document.getElementById("root")!์™€ ๊ฐ™์€ non-null assertion(!) ์‚ฌ์šฉ ์‹œ, root ์—˜๋ฆฌ๋จผํŠธ๊ฐ€ ์—†์„ ๊ฒฝ์šฐ ๋Ÿฐํƒ€์ž„ ์˜ค๋ฅ˜๋กœ ์ด์–ด์งˆ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
    • ์ œ์•ˆ: root ์—˜๋ฆฌ๋จผํŠธ ์กด์žฌ ์—ฌ๋ถ€๋ฅผ ํ™•์ธํ•˜๋Š” ๋ฐฉ์–ด์ ์ธ ์ฝ”๋“œ๋ฅผ ์ถ”๊ฐ€ํ•˜์„ธ์š”.
  • ๊ฐœ๋ฐœ ํšจ์œจ: <React.StrictMode>๋กœ <App /> ์ปดํฌ๋„ŒํŠธ๋ฅผ ๊ฐ์‹ธ ๊ฐœ๋ฐœ ๋ชจ๋“œ์—์„œ ์ž ์žฌ์ ์ธ ๋ฌธ์ œ ์‹๋ณ„์— ๋„์›€์„ ๋ฐ›์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

src/page/Homepage.tsx

  • ์„ฑ๋Šฅ ๋ฌธ์ œ: CartList์™€ CartSummary ์ปดํฌ๋„ŒํŠธ์— prop์œผ๋กœ ์ „๋‹ฌ๋˜๋Š” onIncrease, onDecrease, onClear ํ•จ์ˆ˜๋“ค์ด ๋งค ๋ Œ๋”๋ง๋งˆ๋‹ค ์ƒˆ๋กœ์šด ์ธ์Šคํ„ด์Šค๋กœ ์ƒ์„ฑ๋˜์–ด ์ž์‹ ์ปดํฌ๋„ŒํŠธ์˜ ๋ถˆํ•„์š”ํ•œ ๋ฆฌ๋ Œ๋”๋ง์„ ์œ ๋ฐœํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
    • ์ œ์•ˆ: useCallback ํ›…์„ ์‚ฌ์šฉํ•˜์—ฌ ์ด ์ฝœ๋ฐฑ ํ•จ์ˆ˜๋“ค์˜ ์•ˆ์ •์ ์ธ ์ฐธ์กฐ๋ฅผ ๋ณด์žฅํ•˜์„ธ์š”.
  • ์„ฑ๋Šฅ/๋ฆฌํŒฉํ† ๋ง: useSelector๋ฅผ ํ†ตํ•ด state.cart ์ „์ฒด๋ฅผ ๊ฐ€์ ธ์™€ ๊ตฌ์กฐ๋ถ„ํ•ด ํ• ๋‹นํ•˜๋Š” ๋Œ€์‹ , amount์™€ total ๊ฐ™์€ ํŒŒ์ƒ ์ƒํƒœ๋Š” Redux Selector (ํ˜น์€ Zustand Getter)๋ฅผ ํ†ตํ•ด ๊ฐœ๋ณ„์ ์œผ๋กœ ๊ฐ€์ ธ์˜ค๋„๋ก ๋ณ€๊ฒฝํ•˜๋Š” ๊ฒƒ์ด ๋” ํšจ์œจ์ ์ž…๋‹ˆ๋‹ค.
  • ์ฝ”๋“œ ํ’ˆ์งˆ: ๋””๋ฒ„๊น…์šฉ console.log๊ฐ€ ๋‚จ์•„์žˆ์Šต๋‹ˆ๋‹ค.
    • ์ œ์•ˆ: ํ”„๋กœ๋•์…˜ ์ฝ”๋“œ์— ๋ถˆํ•„์š”ํ•œ console.log๋Š” ์ œ๊ฑฐํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

src/component/Navbar.tsx

  • ์ฝ”๋“œ ํ’ˆ์งˆ: ๋‚ด๋น„๊ฒŒ์ด์…˜ ๋ฐ”๋ฅผ div ํƒœ๊ทธ๋กœ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.
    • ์ œ์•ˆ: <div className="w-full ...">๋ฅผ <nav className="w-full ...">๋กœ ๋ณ€๊ฒฝํ•˜์—ฌ ์‹œ๋งจํ‹ฑํ•œ HTML ๊ตฌ์กฐ๋ฅผ ๋”ฐ๋ฅด์„ธ์š”.
  • ์Šคํƒ€์ผ๋ง: h-25๋Š” ํ‘œ์ค€ Tailwind CSS ํด๋ž˜์Šค๊ฐ€ ์•„๋‹™๋‹ˆ๋‹ค.
    • ์ œ์•ˆ: h-24 ๋˜๋Š” h-28 ๋“ฑ ์œ ํšจํ•œ ํด๋ž˜์Šค๋ฅผ ์‚ฌ์šฉํ•˜๊ฑฐ๋‚˜, h-[6.25rem]์™€ ๊ฐ™์ด Arbitrary value๋ฅผ ์‚ฌ์šฉํ•˜์„ธ์š”.
  • ๋ณ€์ˆ˜๋ช…/์ฃผ์„: "dongyeol"์ด๋ผ๋Š” ํ…์ŠคํŠธ๊ฐ€ ํ•˜๋“œ์ฝ”๋”ฉ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค.
    • ์ œ์•ˆ: ์•ฑ์˜ ํƒ€์ดํ‹€์ด๋ผ๋ฉด title prop์œผ๋กœ ๋ฐ›๊ฑฐ๋‚˜ ์ƒ์ˆ˜๋กœ ๊ด€๋ฆฌํ•˜์—ฌ ์žฌ์‚ฌ์šฉ์„ฑ์„ ๋†’์ด์„ธ์š”.

src/component/CartList.tsx

  • ์„ฑ๋Šฅ ๋ฌธ์ œ: items.map ๋‚ด๋ถ€์—์„œ onIncrease, onDecrease์— ์ „๋‹ฌ๋˜๋Š” ์ฝœ๋ฐฑ ํ•จ์ˆ˜ () => onIncrease(item.id)์™€ () => onDecrease(item.id)๊ฐ€ ๋งค ๋ Œ๋”๋ง๋งˆ๋‹ค ์ƒˆ๋กœ ์ƒ์„ฑ๋˜์–ด CartItem ์ปดํฌ๋„ŒํŠธ์˜ ๋ถˆํ•„์š”ํ•œ ๋ฆฌ๋ Œ๋”๋ง์„ ์œ ๋ฐœํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
    • ์ œ์•ˆ: CartItem ์ปดํฌ๋„ŒํŠธ๊ฐ€ onIncrease์™€ onDecrease ํ•จ์ˆ˜ ์ž์ฒด๋ฅผ prop์œผ๋กœ ๋ฐ›๊ณ , CartItem ๋‚ด๋ถ€์—์„œ onClick={() => onIncrease(item.id)} ํ˜•ํƒœ๋กœ ํ˜ธ์ถœํ•˜๋„๋ก ๊ตฌ์กฐ๋ฅผ ๋ณ€๊ฒฝํ•˜์—ฌ, Homepage.tsx์˜ useCallback๊ณผ ์‹œ๋„ˆ์ง€๋ฅผ ๋‚ด๋„๋ก ํ•˜์„ธ์š”.

src/component/CartItem.tsx

  • ํƒ€์ž…/์„ฑ๋Šฅ: item.price๊ฐ€ string ํƒ€์ž…์œผ๋กœ ์ „๋‹ฌ๋˜์–ด Number(item.price).toLocaleString()์œผ๋กœ ๋งค ๋ Œ๋”๋ง๋งˆ๋‹ค ๋ณ€ํ™˜๋ฉ๋‹ˆ๋‹ค.
    • ์ œ์•ˆ: price๋ฅผ number ํƒ€์ž…์œผ๋กœ ์ผ๊ด€๋˜๊ฒŒ ์ •์˜ํ•˜๊ณ , toLocaleString() ์—ฐ์‚ฐ์€ useMemo๋กœ ์บ์‹ฑํ•˜๋Š” ๊ฒƒ์„ ๊ณ ๋ คํ•˜์„ธ์š”.
  • ์ฝ”๋“œ ํ’ˆ์งˆ: ํŒŒ์ผ ์ƒ๋‹จ์— // components/CartItem.tsx ์ฃผ์„์ด ์ค‘๋ณต๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค.
    • ์ œ์•ˆ: ๋ถˆํ•„์š”ํ•œ ์ค‘๋ณต ์ฃผ์„์„ ์ œ๊ฑฐํ•˜์„ธ์š”.

src/component/CartSummary.tsx

  • ์„ฑ๋Šฅ: totalPrice.toLocaleString() ์—ญ์‹œ ๋ Œ๋”๋ง๋  ๋•Œ๋งˆ๋‹ค ํ˜ธ์ถœ๋ฉ๋‹ˆ๋‹ค.
    • ์ œ์•ˆ: useMemo ํ›…์„ ์‚ฌ์šฉํ•˜์—ฌ ์บ์‹ฑํ•˜๋Š” ๊ฒƒ์„ ๊ณ ๋ คํ•˜์„ธ์š”.
  • ์ฝ”๋“œ ํ’ˆ์งˆ: ๋””๋ฒ„๊น…์šฉ console.log๊ฐ€ ๋‚จ์•„์žˆ์Šต๋‹ˆ๋‹ค.
    • ์ œ์•ˆ: ํ”„๋กœ๋•์…˜ ์ฝ”๋“œ์— ๋ถˆํ•„์š”ํ•œ console.log๋Š” ์ œ๊ฑฐํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

src/component/ClearCartModal.tsx

  • UI/UX/์ ‘๊ทผ์„ฑ: "๋„ค" ๋ฒ„ํŠผ๊ณผ "์•„๋‹ˆ์š”" ๋ฒ„ํŠผ์˜ HTML ๊ตฌ์กฐ๊ฐ€ ์ผ๊ด€๋˜์ง€ ์•Š์•„ ๋ ˆ์ด์•„์›ƒ ์ •๋ ฌ์ด ์–ด์ƒ‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋˜ํ•œ, ๋ชจ๋‹ฌ์€ ๊ธฐ๋ณธ์ ์ธ ์ ‘๊ทผ์„ฑ ๊ณ ๋ ค์‚ฌํ•ญ์„ ์ถ”๊ฐ€ํ•˜๋ฉด ์‚ฌ์šฉ์ž ๊ฒฝํ—˜์ด ํฌ๊ฒŒ ํ–ฅ์ƒ๋ฉ๋‹ˆ๋‹ค.
    • ์ œ์•ˆ:
      1. ๋‘ ๋ฒ„ํŠผ์„ ํ•˜๋‚˜์˜ div๋กœ ๋ฌถ์–ด flex justify-end gap-2์™€ ๊ฐ™์€ ์Šคํƒ€์ผ์„ ์ผ๊ด€๋˜๊ฒŒ ์ ์šฉํ•ฉ๋‹ˆ๋‹ค.
      2. ๋ชจ๋‹ฌ์˜ ๋ฃจํŠธ div์— role="dialog"์™€ aria-modal="true"๋ฅผ ์ถ”๊ฐ€ํ•˜์—ฌ ์Šคํฌ๋ฆฐ ๋ฆฌ๋” ์‚ฌ์šฉ์ž๋ฅผ ์œ„ํ•œ ์‹œ๋งจํ‹ฑ ์ •๋ณด๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.
      3. ๋ชจ๋‹ฌ์ด ์—ด๋ ธ์„ ๋•Œ ์ฒซ ๋ฒˆ์งธ ์ƒํ˜ธ์ž‘์šฉ ๊ฐ€๋Šฅํ•œ ์š”์†Œ์— ์ž๋™์œผ๋กœ ํฌ์ปค์Šค๋ฅผ ์ด๋™ํ•˜๊ณ , ๋‹ซํž ๋•Œ ์›๋ž˜ ํŠธ๋ฆฌ๊ฑฐ ์š”์†Œ๋กœ ํฌ์ปค์Šค๋ฅผ ๋ณต์›ํ•˜๋Š” ๋กœ์ง์„ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.
      4. Escape ํ‚ค๋ฅผ ๋ˆŒ๋Ÿฌ ๋ชจ๋‹ฌ์„ ๋‹ซ์„ ์ˆ˜ ์žˆ๋„๋ก ์ด๋ฒคํŠธ ๋ฆฌ์Šค๋„ˆ๋ฅผ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.
  • ์ฝ”๋“œ ํ’ˆ์งˆ: ํŒŒ์ผ ์ƒ๋‹จ์— // components/ClearCartModal.tsx ์ฃผ์„์ด ์ค‘๋ณต๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค.
    • ์ œ์•ˆ: ๋ถˆํ•„์š”ํ•œ ์ค‘๋ณต ์ฃผ์„์„ ์ œ๊ฑฐํ•˜์„ธ์š”.

src/constants/cartItems.ts

  • ํƒ€์ž… ๊ฐœ์„ : price ๊ฐ’์ด string์œผ๋กœ ์ •์˜๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค.
    • ์ œ์•ˆ: ์ˆซ์ž ์—ฐ์‚ฐ์— ์‚ฌ์šฉ๋  ๊ฐ’์ด๋ฏ€๋กœ number ํƒ€์ž…์œผ๋กœ ์ •์˜ํ•˜๋Š” ๊ฒƒ์ด ๋” ์ ์ ˆํ•ฉ๋‹ˆ๋‹ค.

src/types/cart.ts

  • ํƒ€์ž… ๊ฐœ์„ : price: string; ๋ถ€๋ถ„์ด ํ•ต์‹ฌ์ ์ธ ํƒ€์ž… ๊ฐœ์„ ์ ์ž…๋‹ˆ๋‹ค.
    • ์ œ์•ˆ: price: number;๋กœ ๋ณ€๊ฒฝํ•˜๊ณ , CartItem ํƒ€์ž…์„ src/constants/cartItems.ts์—์„œ ์ถ”๋ก ํ•˜์—ฌ ์ค‘์•™ ์ง‘์ค‘ํ™”๋œ src/types/cart.ts์— ์ •์˜ํ•œ ํ›„ ํ•„์š”ํ•œ ๋ชจ๋“  ๊ณณ์—์„œ importํ•˜์—ฌ ์‚ฌ์šฉํ•˜๋„๋ก ํ•ฉ๋‹ˆ๋‹ค.

src/features/cart/cartSlice.ts (Redux Toolkit ์‚ฌ์šฉ ์‹œ)

  • ํƒ€์ž… ๊ฐœ์„ : price๊ฐ€ string์ธ ๋ฌธ์ œ์ ์ด ์—ฌ์ „ํžˆ ์กด์žฌํ•ฉ๋‹ˆ๋‹ค.
  • ์ค‘๋ณต ์ฝ”๋“œ/๋ฆฌํŒฉํ† ๋ง/์„ฑ๋Šฅ:
    • calcTotals ํ•จ์ˆ˜๊ฐ€ increase, decrease, removeItem ๋ฆฌ๋“€์„œ ๋์—์„œ ๋งค๋ฒˆ ํ˜ธ์ถœ๋˜์–ด cartItems ์ „์ฒด๋ฅผ ์ˆœํšŒํ•˜๋ฉฐ amount์™€ total์„ ์žฌ๊ณ„์‚ฐํ•ฉ๋‹ˆ๋‹ค.
    • amount์™€ total์€ cartItems๋กœ๋ถ€ํ„ฐ ํŒŒ์ƒ๋˜๋Š” ๊ฐ’์ž…๋‹ˆ๋‹ค. Redux Selector๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํ•„์š”ํ•  ๋•Œ ๊ณ„์‚ฐํ•˜๋Š” ๊ฒƒ์ด ๋” Redux์˜ ์ฒ ํ•™์— ๋ถ€ํ•ฉํ•˜๋ฉฐ, ์ƒํƒœ ๋ถˆ์ผ์น˜ ์œ„ํ—˜์„ ์ค„์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
    • calculateTotals ๋ฆฌ๋“€์„œ๋Š” ๋ถˆํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.
  • ์ดˆ๊ธฐ ์ƒํƒœ ๋ถˆ๋ณ€์„ฑ: initialState.cartItems๊ฐ€ cartItems ์ƒ์ˆ˜๋ฅผ ์ง์ ‘ ์ฐธ์กฐํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. item.amount += 1๊ณผ ๊ฐ™์ด ๋ฆฌ๋“€์„œ ๋‚ด์—์„œ item ๊ฐ์ฒด ์†์„ฑ์„ ๋ณ€๊ฒฝํ•˜๋ฏ€๋กœ, ์ด initialState๋ฅผ deep copy๋กœ ๋งŒ๋“ค์–ด์„œ ์›๋ณธ cartItems ์ƒ์ˆ˜๊ฐ€ ์˜ํ–ฅ์„ ๋ฐ›์ง€ ์•Š๋„๋ก ํ•˜๋Š” ๊ฒƒ์ด ์•ˆ์ „ํ•ฉ๋‹ˆ๋‹ค.

src/store/useCartStore.ts (Zustand ์‚ฌ์šฉ ์‹œ)

  • ์„ฑ๋Šฅ ๋ฌธ์ œ: calcTotals ํ•จ์ˆ˜๊ฐ€ increase, decrease, removeItem ์•ก์…˜์ด ๋ฐœ์ƒํ•  ๋•Œ๋งˆ๋‹ค amount์™€ total์„ ๋‹ค์‹œ ๊ณ„์‚ฐํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ์นดํŠธ ์•„์ดํ…œ ์ˆ˜๊ฐ€ ๋งŽ์•„์งˆ ๊ฒฝ์šฐ ์ƒํƒœ ์—…๋ฐ์ดํŠธ ์‹œ ๋งค๋ฒˆ ์ „์ฒด ์•„์ดํ…œ์„ ์ˆœํšŒํ•˜๋Š” ๋น„์šฉ์„ ๊ณ ๋ คํ•ด๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
    • ์ œ์•ˆ: increase, decrease, removeItem ์•ก์…˜ ๋‚ด์—์„œ amount์™€ total์„ ํ•ด๋‹น ์•„์ดํ…œ์˜ ๋ณ€ํ™”๋Ÿ‰๋งŒํผ๋งŒ ์ ์ง„์ ์œผ๋กœ ์—…๋ฐ์ดํŠธํ•˜๋„๋ก ๋กœ์ง์„ ์ˆ˜์ •ํ•˜๋Š” ๊ฒƒ์„ ๊ณ ๋ คํ•˜์„ธ์š”.
  • ํƒ€์ž… ๊ฐœ์„ : CartItem์˜ price๊ฐ€ string ํƒ€์ž…์ž…๋‹ˆ๋‹ค.
    • ์ œ์•ˆ: number ํƒ€์ž…์œผ๋กœ ๋ณ€๊ฒฝํ•˜๊ณ , src/types/cart.ts์— ์ •์˜๋œ ์ค‘์•™ ์ง‘์ค‘ํ™”๋œ ํƒ€์ž…์„ ์‚ฌ์šฉํ•˜๋„๋ก ํ•ฉ๋‹ˆ๋‹ค.
  • ํƒ€์ž… ๊ฐœ์„ : CartItem ํƒ€์ž…์ด (typeof cartItems)[number];์™€ ๊ฐ™์ด ์ถ”๋ก  ๋ฐฉ์‹์œผ๋กœ ์ •์˜๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค.
    • ์ œ์•ˆ: src/types/cart.ts์— ์ •์˜๋œ ํƒ€์ž…์„ ๋ช…์‹œ์ ์œผ๋กœ importํ•˜์—ฌ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค.
  • ์ฝ”๋“œ ํ’ˆ์งˆ: ํŒŒ์ผ ์ƒ๋‹จ ์ฃผ์„ // src/stores/useCartStore.ts๋Š” ํŒŒ์ผ ๊ตฌ์กฐ๊ฐ€ ๋ช…ํ™•ํ•˜๋ฏ€๋กœ ์ œ๊ฑฐํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค.

src/store/useModalStore.ts (Zustand ์‚ฌ์šฉ ์‹œ)

  • ์ฝ”๋“œ ํ’ˆ์งˆ: ํŒŒ์ผ ์ƒ๋‹จ ์ฃผ์„ // src/stores/useModalStore.ts๋Š” ์ œ๊ฑฐํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค.

src/store/store.ts (Redux Toolkit ์‚ฌ์šฉ ์‹œ)

  • ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ: RootState ๋ฐ AppDispatch ํƒ€์ž… ์ •์˜๋Š” ํ‘œ์ค€์ ์ด๊ณ  ์ž˜ ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค.

src/pages/UseReducerPage.tsx

  • ํƒ€์ž… ๊ฐœ์„ ์ : IAction ์ธํ„ฐํŽ˜์ด์Šค์—์„œ payload๋ฅผ ์„ ํƒ์ ์œผ๋กœ ์ •์˜ํ•˜๊ณ  ์žˆ์–ด reducer ๋‚ด์—์„œ undefined ๊ฐ€๋Šฅ์„ฑ์„ ํ•ญ์ƒ ๊ณ ๋ คํ•ด์•ผ ํ•˜๋ฉฐ, ํŠน์ • type์—๋งŒ payload๊ฐ€ ํ•„์š”ํ•จ์—๋„ ๋ชจ๋“  ์•ก์…˜ ํƒ€์ž…์— payload๊ฐ€ ์กด์žฌํ•˜๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ๋ณด์ž…๋‹ˆ๋‹ค.
    • ์ œ์•ˆ: ๊ฐ ์•ก์…˜ type์— ๋”ฐ๋ผ ํ•„์š”ํ•œ payload๋ฅผ ๋ช…ํ™•ํžˆ ์ •์˜ํ•˜๋Š” Discriminated Union ํŒจํ„ด์„ ์‚ฌ์šฉํ•˜์„ธ์š”.
  • ํƒ€์ž…/์ธํ„ฐํŽ˜์ด์Šค ๋„ค์ด๋ฐ: IState, IAction ๋“ฑ I ์ ‘๋‘์‚ฌ๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ํ˜„๋Œ€ TypeScript ์ปค๋ฎค๋‹ˆํ‹ฐ์—์„œ๋Š” ์ ‘๋‘์‚ฌ ์‚ฌ์šฉ์„ ๊ถŒ์žฅํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
    • ์ œ์•ˆ: State, Action๊ณผ ๊ฐ™์ด ์ง๊ด€์ ์ธ ์ด๋ฆ„์„ ์‚ฌ์šฉํ•˜์„ธ์š”.
  • ์ฝ”๋“œ ํ’ˆ์งˆ: ๋””๋ฒ„๊น…์šฉ console.log ๊ตฌ๋ฌธ์ด ํฌํ•จ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค.
    • ์ œ์•ˆ: ๋ณ‘ํ•ฉ ์ „ ๋ฐ˜๋“œ์‹œ ์ œ๊ฑฐํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
  • ๋กœ์ง ์ผ๊ด€์„ฑ: INCREASE ์•ก์…˜ ๋””์ŠคํŒจ์น˜ ์‹œ payload: 3์„ ์ „๋‹ฌํ•˜์ง€๋งŒ, reducer๋Š” ์ด๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ณ  ํ•ญ์ƒ 1์”ฉ ์ฆ๊ฐ€์‹œํ‚ต๋‹ˆ๋‹ค.
    • ์ œ์•ˆ: payload๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š”๋‹ค๋ฉด ์ œ๊ฑฐํ•˜๊ฑฐ๋‚˜, reducer์—์„œ payload ๊ฐ’์„ ํ™œ์šฉํ•˜๋„๋ก ๋กœ์ง์„ ์ˆ˜์ •ํ•˜์„ธ์š”.
  • ๋ฆฌํŒฉํ† ๋ง: IState ์ธํ„ฐํŽ˜์ด์Šค์™€ ์ดˆ๊ธฐ ์ƒํƒœ์— error: string | null; ์†์„ฑ์ด ์ •์˜๋˜์–ด ์žˆ์ง€๋งŒ ์‚ฌ์šฉ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
    • ์ œ์•ˆ: ์‚ฌ์šฉ๋˜์ง€ ์•Š๋Š” ์ƒํƒœ ์†์„ฑ์€ ์ œ๊ฑฐํ•˜์„ธ์š”.
  • ๋ฆฌํŒฉํ† ๋ง: useReducer์˜ ์ดˆ๊ธฐ ์ƒํƒœ ๊ฐ์ฒด๋ฅผ ์ปดํฌ๋„ŒํŠธ ์™ธ๋ถ€์— ์ƒ์ˆ˜๋กœ ์ •์˜ํ•˜๋ฉด ๊ฐ€๋…์„ฑ๊ณผ ์œ ์ง€๋ณด์ˆ˜์„ฑ์ด ํ–ฅ์ƒ๋ฉ๋‹ˆ๋‹ค.
  • ์ฝ”๋“œ ํ’ˆ์งˆ: onClick={(): void => ...}์™€ ๊ฐ™์ด ์ฝœ๋ฐฑ ํ•จ์ˆ˜์— ๋ช…์‹œ์ ์œผ๋กœ : void๋ฅผ ๋ถ™์ด๋Š” ๊ฒƒ์€ ๋Œ€๋ถ€๋ถ„์˜ ๊ฒฝ์šฐ ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ๊ฐ€ ์ž๋™์œผ๋กœ ์ถ”๋ก ํ•˜๋ฏ€๋กœ ์ƒ๋žต ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.

src/pages/UseReducerCompany.tsx

  • ํƒ€์ž… ๊ฐœ์„ ์ : IAction ์ธํ„ฐํŽ˜์ด์Šค์˜ payload ์ •์˜์— Discriminated Union ํŒจํ„ด์„ ์ ์šฉํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค. (UseReducerPage.tsx์™€ ๋™์ผํ•œ ๋งฅ๋ฝ)
  • ํƒ€์ž…/์ธํ„ฐํŽ˜์ด์Šค ๋„ค์ด๋ฐ: IState, IAction, TActionType ๋“ฑ I ๋˜๋Š” T ์ ‘๋‘์‚ฌ๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.
    • ์ œ์•ˆ: State, Action, ActionType๊ณผ ๊ฐ™์ด ์ง๊ด€์ ์ธ ์ด๋ฆ„์„ ์‚ฌ์šฉํ•˜์„ธ์š”.
  • UX ๊ฐœ์„ : ์œ ํšจํ•˜์ง€ ์•Š์€ ์ง๋ฌด ์ž…๋ ฅ ์‹œ input ํ•„๋“œ๊ฐ€ ์œ ํšจํ•˜์ง€ ์•Š์€ ๊ฐ’์„ ์œ ์ง€ํ•˜์—ฌ ์‚ฌ์šฉ์ž์—๊ฒŒ ํ˜ผ๋ž€์„ ์ค„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
    • ์ œ์•ˆ: dispatch ํ˜ธ์ถœ ํ›„, ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ ๊ฒฐ๊ณผ์— ๋”ฐ๋ผ input ํ•„๋“œ์˜ ๋กœ์ปฌ ์ƒํƒœ๋ฅผ ์ดˆ๊ธฐํ™”ํ•˜๊ฑฐ๋‚˜ ์œ ํšจํ•œ ๊ฒฝ์šฐ์—๋งŒ ์ดˆ๊ธฐํ™”ํ•˜๋„๋ก ๋กœ์ง์„ ์ถ”๊ฐ€ํ•˜์—ฌ ์‚ฌ์šฉ์ž์—๊ฒŒ ๋ช…ํ™•ํ•œ ํ”ผ๋“œ๋ฐฑ์„ ์ œ๊ณตํ•˜๋Š” ๊ฒƒ์„ ๊ณ ๋ คํ•˜์„ธ์š”.
  • ์ฝ”๋“œ ํ’ˆ์งˆ: ์—๋Ÿฌ ๋ฉ”์‹œ์ง€๋ฅผ ํ‘œ์‹œํ•˜๋Š” <p> ํƒœ๊ทธ์— className="text-red-500 font-2xl" ํด๋ž˜์Šค๊ฐ€ ์ ์šฉ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค. font-2xl์€ ํ‘œ์ค€ Tailwind CSS ํด๋ž˜์Šค๊ฐ€ ์•„๋‹™๋‹ˆ๋‹ค.
    • ์ œ์•ˆ: text-2xl์„ ์‚ฌ์šฉํ•˜์„ธ์š”.
  • ์ฝ”๋“œ ํ’ˆ์งˆ: ์ฃผ์„ ์ฒ˜๋ฆฌ๋œ useState ๋ฐ changeDepartment ๋กœ์ง์€ ์ œ๊ฑฐํ•˜์—ฌ ๊น”๋”ํ•˜๊ฒŒ ์œ ์ง€ํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค.

์ตœ์ข… ๊ตฌ์ฒด์  ๊ฐœ์„  ์ œ์•ˆ (ํ•ต์‹ฌ 8๊ฐ€์ง€)

  1. ์ƒํƒœ ๊ด€๋ฆฌ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ํ†ต์ผ (Critical)

    • ๋ฌธ์ œ: Redux Toolkit (Files: src/features/cart/cartSlice.ts, src/features/modal/modalSlice.ts, src/store/store.ts)๊ณผ Zustand (Files: src/store/useCartStore.ts, src/store/useModalStore.ts)๋ฅผ ๋™์‹œ์—, ๋™์ผํ•œ ๊ด€์‹ฌ์‚ฌ(์žฅ๋ฐ”๊ตฌ๋‹ˆ, ๋ชจ๋‹ฌ)์— ๋Œ€ํ•ด ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋Š” ํ˜ผ๋ž€, ๋””๋ฒ„๊น… ์–ด๋ ค์›€, ์œ ์ง€๋ณด์ˆ˜ ๋น„์šฉ ์ฆ๊ฐ€๋ฅผ ์•ผ๊ธฐํ•ฉ๋‹ˆ๋‹ค.
    • ์ œ์•ˆ: Redux Toolkit๊ณผ Zustand ์ค‘ ํ•˜๋‚˜๋ฅผ ์„ ํƒํ•˜์—ฌ ๋ชจ๋“  ์ „์—ญ ์ƒํƒœ ๊ด€๋ฆฌ์— ์ผ๊ด€๋˜๊ฒŒ ์‚ฌ์šฉํ•˜๋„๋ก ๊ฒฐ์ •ํ•˜๊ณ , ๋ถˆํ•„์š”ํ•œ ์Šคํ† ์–ด ํŒŒ์ผ๊ณผ ๊ด€๋ จ ์ฝ”๋“œ๋ฅผ ๋ชจ๋‘ ์ œ๊ฑฐํ•˜์„ธ์š”. (ํ˜„์žฌ Homepage.tsx๋Š” Zustand ํ›…์„ ์‚ฌ์šฉํ•˜๋ฏ€๋กœ, Zustand๋ฅผ ์œ ์ง€ํ•˜๊ณ  Redux Toolkit ๊ด€๋ จ ํŒŒ์ผ์„ ์ œ๊ฑฐํ•˜๋Š” ๋ฐฉํ–ฅ์„ ๊ถŒ์žฅํ•ฉ๋‹ˆ๋‹ค.)
  2. price ํ•„๋“œ๋ฅผ number ํƒ€์ž…์œผ๋กœ ํ†ต์ผํ•˜๊ณ , ์ดˆ๊ธฐ ๋กœ๋”ฉ ์‹œ์ ์— ํ•œ ๋ฒˆ๋งŒ ํŒŒ์‹ฑํ•˜๋„๋ก ๋ณ€๊ฒฝํ•˜์„ธ์š”.

    • ๋ฌธ์ œ: src/type/cart.ts์™€ src/constants/cartItems.ts์—์„œ price๊ฐ€ string์œผ๋กœ ์ •์˜๋˜์–ด ์žˆ์ง€๋งŒ, CartItem.tsx์™€ calcTotals ํ•จ์ˆ˜์—์„œ ๋งค๋ฒˆ Number()๋กœ ๋ณ€ํ™˜ํ•˜์—ฌ ์‚ฌ์šฉ๋˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.
    • ์ œ์•ˆ:
      1. src/types/cart.ts (ํ˜น์€ ์ƒˆ๋กœ ์ƒ์„ฑ)์˜ CartItem ํƒ€์ž…์„ price: number;๋กœ ๋ณ€๊ฒฝํ•ฉ๋‹ˆ๋‹ค.
      2. src/constants/cartItems.ts์˜ cartItems ๋ฐฐ์—ด ๋‚ด ๋ชจ๋“  price ๊ฐ’์„ ์ˆซ์ž๋กœ ์ง์ ‘ ๋ณ€๊ฒฝํ•ฉ๋‹ˆ๋‹ค (์˜ˆ: "25000" -> 25000).
      3. Zustand ์Šคํ† ์–ด์˜ initialState (๋˜๋Š” Redux cartSlice์˜ initialState)๋ฅผ ์ƒ์„ฑํ•  ๋•Œ, cartItems ์ƒ์ˆ˜๋ฅผ ๋งตํ•‘ํ•˜์—ฌ price๋ฅผ Number(item.price)๋กœ ๋ณ€ํ™˜ ํ›„ ์ €์žฅํ•ฉ๋‹ˆ๋‹ค.
      4. src/component/CartItem.tsx์—์„œ Number(item.price).toLocaleString()์„ item.price.toLocaleString()์œผ๋กœ ๋ณ€๊ฒฝํ•ฉ๋‹ˆ๋‹ค.
      5. calcTotals ํ•จ์ˆ˜์—์„œ Number(item.price)๋ฅผ item.price๋กœ ๋ณ€๊ฒฝํ•ฉ๋‹ˆ๋‹ค.
  3. Redux Slice (๋˜๋Š” Zustand Store) ๋‚ด ํ•ฉ๊ณ„ ๊ณ„์‚ฐ ๋กœ์ง์„ ์ฆ๋ถ„ ์—…๋ฐ์ดํŠธ๋กœ ์ตœ์ ํ™”ํ•˜๊ณ , ํŒŒ์ƒ๋œ ์ƒํƒœ๋ฅผ Selector๋กœ ๊ด€๋ฆฌํ•˜์„ธ์š”.

    • ๋ฌธ์ œ: increase, decrease, removeItem ์•ก์…˜๋งˆ๋‹ค calcTotals๊ฐ€ ์ „์ฒด cartItems๋ฅผ ์ˆœํšŒํ•˜๋ฉฐ amount์™€ total์„ ์žฌ๊ณ„์‚ฐํ•ฉ๋‹ˆ๋‹ค. amount์™€ total์€ cartItems๋กœ๋ถ€ํ„ฐ ํŒŒ์ƒ๋˜๋Š” ๊ฐ’์ž…๋‹ˆ๋‹ค.
    • ์ œ์•ˆ:
      • Zustand ์‚ฌ์šฉ ์‹œ: increase, decrease, removeItem ์•ก์…˜ ๋‚ด์—์„œ amount์™€ total์„ ํ•ด๋‹น ์•„์ดํ…œ์˜ ๋ณ€ํ™”๋Ÿ‰๋งŒํผ๋งŒ ์ ์ง„์ ์œผ๋กœ ์—…๋ฐ์ดํŠธํ•˜๋„๋ก ๋กœ์ง์„ ์ˆ˜์ •ํ•ฉ๋‹ˆ๋‹ค.
      • Redux Toolkit ์‚ฌ์šฉ ์‹œ: CartState์—์„œ amount์™€ total ํ•„๋“œ๋ฅผ ์ œ๊ฑฐํ•˜๊ณ , createSelector (reselect ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ) ๋˜๋Š” ์ผ๋ฐ˜ ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ cartItems๋กœ๋ถ€ํ„ฐ totalAmount์™€ totalPrice๋ฅผ ๊ณ„์‚ฐํ•˜๋Š” selector๋ฅผ ์ •์˜ํ•˜์—ฌ Homepage.tsx ๋“ฑ์—์„œ ์‚ฌ์šฉํ•˜๋„๋ก ํ•ฉ๋‹ˆ๋‹ค. ๋ชจ๋“  ๋ฆฌ๋“€์„œ์—์„œ amount์™€ total์„ ์ง์ ‘ ์—…๋ฐ์ดํŠธํ•˜๋Š” ๋กœ์ง๊ณผ calculateTotals ๋ฆฌ๋“€์„œ๋ฅผ ์ œ๊ฑฐํ•ฉ๋‹ˆ๋‹ค.
  4. Homepage ์ปดํฌ๋„ŒํŠธ์˜ ์ฝœ๋ฐฑ ํ•จ์ˆ˜์— useCallback์„ ์ ์šฉํ•˜์—ฌ ๋ถˆํ•„์š”ํ•œ ๋ฆฌ๋ Œ๋”๋ง์„ ๋ฐฉ์ง€ํ•˜์„ธ์š”.

    • ๋ฌธ์ œ: src/page/Homepage.tsx์—์„œ CartList์™€ CartSummary์— onIncrease, onDecrease, onClear ์ฝœ๋ฐฑ ํ•จ์ˆ˜๋ฅผ ์ „๋‹ฌํ•  ๋•Œ ๋งค ๋ Œ๋”๋ง๋งˆ๋‹ค ์ƒˆ๋กœ์šด ํ•จ์ˆ˜ ์ฐธ์กฐ๊ฐ€ ์ƒ์„ฑ๋˜์–ด ์ž์‹ ์ปดํฌ๋„ŒํŠธ์˜ ๋ถˆํ•„์š”ํ•œ ๋ฆฌ๋ Œ๋”๋ง์„ ์œ ๋ฐœํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
    • ์ œ์•ˆ: useCallback ํ›…์„ ์‚ฌ์šฉํ•˜์—ฌ ์ด๋“ค ํ•จ์ˆ˜๊ฐ€ dispatch (ํ˜น์€ Zustand์˜ increase, decrease ํ•จ์ˆ˜) ์˜์กด์„ฑ ํ•˜์— ์•ˆ์ •์ ์ธ ์ฐธ์กฐ๋ฅผ ๊ฐ–๋„๋ก ๋ณ€๊ฒฝํ•ฉ๋‹ˆ๋‹ค. ๋˜ํ•œ, CartList ์ปดํฌ๋„ŒํŠธ๊ฐ€ CartItem ์ปดํฌ๋„ŒํŠธ๋กœ item.id์™€ increase/decrease ํ•จ์ˆ˜ ์ž์ฒด๋ฅผ ๋ฐ›๋„๋ก ๋ณ€๊ฒฝํ•˜์—ฌ CartItem ๋‚ด์—์„œ onClick={() => onIncrease(item.id)} ํ˜•ํƒœ๋กœ ํ˜ธ์ถœํ•˜๋„๋ก ํ•ฉ๋‹ˆ๋‹ค.
  5. useReducer ๊ด€๋ จ ํŒŒ์ผ์— Discriminated Union ํŒจํ„ด ๋ฐ ํ˜„๋Œ€์ ์ธ ํƒ€์ž… ๋„ค์ด๋ฐ์„ ์ ์šฉํ•˜์„ธ์š”.

    • ๋ฌธ์ œ: src/pages/UseReducerPage.tsx์™€ src/pages/UseReducerCompany.tsx์˜ IAction ์ธํ„ฐํŽ˜์ด์Šค์—์„œ payload ์ •์˜๊ฐ€ ๋ชจํ˜ธํ•˜๋ฉฐ, I ๋˜๋Š” T ์ ‘๋‘์‚ฌ ์‚ฌ์šฉ์€ ํ˜„๋Œ€ TypeScript ์ปจ๋ฒค์…˜์— ๋งž์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
    • ์ œ์•ˆ: ๊ฐ ์•ก์…˜ type์— ๋”ฐ๋ผ ํ•„์š”ํ•œ payload๋ฅผ ๋ช…ํ™•ํžˆ ์ •์˜ํ•˜๋Š” Discriminated Union ํŒจํ„ด์„ ์‚ฌ์šฉํ•˜๊ณ , IState, IAction, TActionType ๋Œ€์‹  State, Action, ActionType๊ณผ ๊ฐ™์ด ์ง๊ด€์ ์ธ ์ด๋ฆ„์„ ์‚ฌ์šฉํ•˜์„ธ์š”.
  6. ClearCartModal์˜ ๋ฒ„ํŠผ ๊ตฌ์กฐ ๋ฐ ์ ‘๊ทผ์„ฑ์„ ๊ฐ•ํ™”ํ•˜์„ธ์š”.

    • ๋ฌธ์ œ: src/component/ClearCartModal.tsx์—์„œ "๋„ค" ๋ฒ„ํŠผ๊ณผ "์•„๋‹ˆ์š”" ๋ฒ„ํŠผ์˜ DOM ๊ตฌ์กฐ๊ฐ€ ๋‹ฌ๋ผ ์‹œ๊ฐ์ ์œผ๋กœ ์ผ๊ด€์„ฑ์ด ๋–จ์–ด์ง€๋ฉฐ, ๋ชจ๋‹ฌ์˜ ๊ธฐ๋ณธ์ ์ธ ์ ‘๊ทผ์„ฑ ๊ณ ๋ ค์‚ฌํ•ญ์ด ๋ถ€์กฑํ•ฉ๋‹ˆ๋‹ค.
    • ์ œ์•ˆ: ๋‘ ๋ฒ„ํŠผ์„ ํ•˜๋‚˜์˜ div๋กœ ๋ฌถ์–ด ์ผ๊ด€๋œ ๋ ˆ์ด์•„์›ƒ์„ ์ ์šฉํ•˜๊ณ , ๋ชจ๋‹ฌ ๋ฃจํŠธ div์— role="dialog", aria-modal="true"๋ฅผ ์ถ”๊ฐ€ํ•˜๋ฉฐ, ํฌ์ปค์Šค ๊ด€๋ฆฌ ๋ฐ Escape ํ‚ค ๋‹ซ๊ธฐ ๊ธฐ๋Šฅ์„ ๊ตฌํ˜„ํ•˜์—ฌ ์ ‘๊ทผ์„ฑ์„ ํ–ฅ์ƒ์‹œํ‚ค์„ธ์š”.
  7. CartItem ํƒ€์ž… ์ •์˜๋ฅผ ์ค‘์•™ํ™”ํ•˜๊ณ  ์ผ๊ด€์„ฑ ์žˆ๊ฒŒ ๊ด€๋ฆฌํ•˜์„ธ์š”.

    • ๋ฌธ์ œ: CartItem ํƒ€์ž… ์ •์˜๊ฐ€ ์—ฌ๋Ÿฌ ๊ณณ์—์„œ ์ค‘๋ณต๋˜๊ฑฐ๋‚˜ ๋ชจํ˜ธํ•˜๊ฒŒ ์ฐธ์กฐ๋˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.
    • ์ œ์•ˆ: src/constants/cartItems.ts์—์„œ ์‹ค์ œ ๋ฐ์ดํ„ฐ์˜ ํƒ€์ž…์„ ์ถ”๋ก ํ•˜์—ฌ src/types/cart.ts (์ƒˆ๋กœ ์ƒ์„ฑํ•˜๊ฑฐ๋‚˜ ๊ธฐ์กด ํŒŒ์ผ ํ™œ์šฉ)์— CartItem ํƒ€์ž…์„ ์ค‘์•™ ์ง‘์ค‘ํ™”ํ•˜์—ฌ ์ •์˜ํ•˜๊ณ , ์ด ํƒ€์ž…์ด ํ•„์š”ํ•œ ๋ชจ๋“  ์ปดํฌ๋„ŒํŠธ์™€ ์Šคํ† ์–ด ํŒŒ์ผ์—์„œ import { CartItem } from '../types/cart';์™€ ๊ฐ™์ด ๊ฐ€์ ธ์™€ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.
  8. ์ฝ”๋“œ ํ’ˆ์งˆ ๊ฐœ์„  (์ฃผ์„, console.log, ์Šคํƒ€์ผ๋ง)

    • ๋ฌธ์ œ: ๋””๋ฒ„๊น…์šฉ console.log๊ฐ€ ๋‚จ์•„์žˆ๊ณ , ๋ถˆํ•„์š”ํ•œ ์ค‘๋ณต ์ฃผ์„์ด ์žˆ์œผ๋ฉฐ, Navbar์˜ h-25์™€ UseReducerCompany์˜ font-2xl ๊ฐ™์€ ์œ ํšจํ•˜์ง€ ์•Š์€ Tailwind ํด๋ž˜์Šค๊ฐ€ ์‚ฌ์šฉ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.
    • ์ œ์•ˆ:
      • ๋ชจ๋“  console.log์™€ ์ฃผ์„ ์ฒ˜๋ฆฌ๋œ ์ฝ”๋“œ๋ฅผ ์ œ๊ฑฐํ•ฉ๋‹ˆ๋‹ค.
      • src/component/CartItem.tsx, src/component/ClearCartModal.tsx, src/store/useCartStore.ts, src/store/useModalStore.ts ๋“ฑ์˜ ํŒŒ์ผ ์ƒ๋‹จ์— ์žˆ๋Š” ์ค‘๋ณต๋˜๊ฑฐ๋‚˜ ๋ถˆํ•„์š”ํ•œ ์ฃผ์„์„ ์ œ๊ฑฐํ•ฉ๋‹ˆ๋‹ค.
      • src/component/Navbar.tsx์˜ h-25๋ฅผ ์œ ํšจํ•œ Tailwind ํด๋ž˜์Šค(์˜ˆ: h-24, h-28)๋‚˜ Arbitrary value๋กœ ์ˆ˜์ •ํ•ฉ๋‹ˆ๋‹ค.
      • src/pages/UseReducerCompany.tsx์˜ font-2xl์„ text-2xl๋กœ ์ˆ˜์ •ํ•ฉ๋‹ˆ๋‹ค.

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

๊ณ ์ƒ ๋งŽ์œผ์…จ์Šต๋‹ˆ๋‹ค!

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.

9์ฃผ์ฐจ๋„ ๊ณ ์ƒํ•˜์…จ์Šต๋‹ˆ๋‹ค

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