Skip to content

kd02109/ShoppingApp

Folders and files

NameName
Last commit message
Last commit date

Latest commit

ย 

History

124 Commits
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 

Repository files navigation

fe-sprint-coz-shopping

๋กœ์ปฌ์—์„œ ์‹œ์ž‘ํ•˜๊ธฐ

  • ํ˜„์žฌ ๋ฐฐํฌ๋œ page์—์„œ๋Š” Mixed Content ์ด์Šˆ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ์ œ๊ณตํ•ด์ฃผ๋Š” api๊ฐ€ http์ด๊ธฐ์— ๋ฐœ์ƒํ•˜๋Š” ๋ฌธ์ œ์ž…๋‹ˆ๋‹ค.
  • fake data๋ฅผ ํ™œ์šฉํ•˜์—ฌ ์ผ์‹œ์ ์ธ ํŽ˜์ด์ง€ ๋™์ž‘์€ ๊ฐ€๋Šฅํ•˜๊ฒŒ ํ•˜์˜€์Šต๋‹ˆ๋‹ค.
  • ๋กœ์ปฌ์—์„œ ์‹œ์ž‘ํ•˜๋Š” ๋ฐฉ์‹์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.
npm i
npm run dev

๊ฐœ์š”

  • ์žฅ๋ฐ”๊ตฌ๋‹ˆ ๊ธฐ๋Šฅ์ด ์žˆ๋Š” ์ƒํ’ˆํŽ˜์ด์ง€๋ฅผ ๊ตฌํ˜„ํ•ฉ๋‹ˆ๋‹ค. ๊ธฐ๋ณธ์ ์ธ ๋””์ž์ธ์€ ํ•ด๋‹น ๋งํฌ์—์„œ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ํ•ด๋‹น ํ”„๋กœ์ ํŠธ์˜ ๋ชฉ์ ์€ ์ฃผ์–ด์ง„ ๋””์ž์ธ์— ๋งž์ถ”์–ด ๊ธฐ๋Šฅ์„ ๊ตฌํ˜„ํ•˜๋Š” ๋ฐฉ๋ฒ•๋ก ์„ ํ•™์Šตํ•ฉ๋‹ˆ๋‹ค.
  • ์—์ž์ผ ๋ฐฉ๋ฒ•๋ก  ์ค‘ ์Šคํฌ๋Ÿผ ๋ฐฉ๋ฒ•์„ ํ™œ์šฉํ•ด์„œ ์ง„ํ–‰ํ•ฉ๋‹ˆ๋‹ค. github์˜ ํ”„๋กœ์ ํŠธ๋ฅผ ํ™œ์šฉํ–ˆ์Šต๋‹ˆ๋‹ค. ๋งํฌ
  • ๋””์ž์ธ ๋งํฌ

๊ธฐ์ˆ ์Šคํƒ

๊ตฌํ˜„ ์š”์†Œ(๋ช…์„ธ์„œ)

Main page(๋ฉ”์ธ ํŽ˜์ด์ง€)

  • path: /
  • Header์™€ Footer๋ฅผ ๊ฐ–๊ณ  ์žˆ์œผ๋ฉฐ, ํ•ด๋‹น GNB์™€ Footer๋Š” ์–ด๋А ํŽ˜์ด์ง€๋ฅผ ๊ฐ€๋”๋ผ๋„ ํ•ญ์ƒ ์กด์žฌํ•ด์•ผ ํ•œ๋‹ค.
    • Header ๋‚ด ํ–„๋ฒ„๊ฑฐ ๋ฒ„ํŠผ ์กด์žฌ, ํ–„๋ฒ„๊ฑฐ ๋ฒ„ํŠผ ํŽผ์น  ์‹œ ๋‚ด๋ถ€์—
      • Header๋Š” ํŽ˜์ด์ง€ ๋‚ด ์Šคํฌ๋กค์ด ๋ฐœ์ƒํ•˜๋”๋ผ๋„ ํ•ญ์ƒ ์ƒ๋‹จ์— ๋ถ™์–ด์žˆ์–ด์•ผ ํ•œ๋‹ค.
      • ๋ฉ”์ธ๋กœ๊ณ  โ†’ ํด๋ฆญํ•˜๋ฉด / ํŽ˜์ด์ง€๋กœ ์ด๋™
      • ํ–„๋ฒ„๊ฑฐ ๋ฒ„ํŠผ
        • ์ƒํ’ˆ๋ฆฌ์ŠคํŠธ โ†’ ํด๋ฆญํ•˜๋ฉด /products/list ํŽ˜์ด์ง€๋กœ ์ด๋™
        • ๋ถ๋งˆํฌํŽ˜์ด์ง€ โ†’ ํด๋ฆญํ•˜๋ฉด /bookmark ํŽ˜์ด์ง€๋กœ ์ด๋™
    • Footer
      • ์ผ๋ จ์˜ ํ…์ŠคํŠธ ์ •๋ณด๋“ค
  • ํ•ด๋‹น ๋ฉ”์ธํŽ˜์ด์ง€์—์„œ๋Š”
    • ๋ชจ๋“  ํƒ€์ž…์˜ ์ƒํ’ˆ ์ •๋ณด๋ฅผ 4๊ฐœ ๋ณด์—ฌ์ค€๋‹ค (ํ•„ํ„ฐ๊ธฐ๋Šฅ ์—†์ด)
      • ๋ณด์—ฌ์ง€๋Š” ์ƒํ’ˆ์˜ ํƒ€์ž…์€ ํ˜ผํ•ฉ๋˜์–ด ์žˆ์„ ์ˆ˜ ์žˆ๋‹ค (์ƒํ’ˆ, ์นดํ…Œ๊ณ ๋ฆฌ, ๊ธฐํš์ „, ๋ธŒ๋žœ๋“œ)
    • ๋ชจ๋“  ํƒ€์ž…์˜ ๋ถ๋งˆํฌ ๋œ ์ƒํ’ˆ ์ •๋ณด๋ฅผ 4๊ฐœ ๋ณด์—ฌ์ค€๋‹ค (ํ•„ํ„ฐ๊ธฐ๋Šฅ ์—†์ด)
      • ๋ณด์—ฌ์ง€๋Š” ์ƒํ’ˆ์˜ ํƒ€์ž…์€ ํ˜ผํ•ฉ๋˜์–ด ์žˆ์„ ์ˆ˜ ์žˆ๋‹ค (์ƒํ’ˆ, ์นดํ…Œ๊ณ ๋ฆฌ, ๊ธฐํš์ „, ๋ธŒ๋žœ๋“œ)

Products list page(์ƒํ’ˆ๋ฆฌ์ŠคํŠธ ํŽ˜์ด์ง€)

  • path: /products/list
  • ์„œ๋ฒ„์—์„œ ์ œ๊ณตํ•˜๋Š” ์ƒํ’ˆ ๋ฆฌ์ŠคํŠธ๋“ค์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋Š” ํŽ˜์ด์ง€์ด๋ฉฐ
    • ๋ฌดํ•œ ์Šคํฌ๋กค์„ ํ†ตํ•ด ์ƒํ’ˆ๋“ค์„ ๊ณ„์† ๋ณด์—ฌ์ค„ ์ˆ˜ ์žˆ์–ด์•ผ ํ•œ๋‹ค .๋ฌดํ•œ์Šคํฌ๋กค์€ ์ฟผ๋ฆฌํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ํ†ตํ•œ ๋งค๋ฒˆ api call์ด ์•„๋‹Œ, ์ตœ์ดˆ 1๋ฒˆ api call์„ ํ†ตํ•ด ์ „์ฒด ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ›์•„์˜จ ํ›„ ์ ์šฉํ•ฉ๋‹ˆ๋‹ค.
  • ์ƒํ’ˆ์€ ๊ฐ ์ƒํ’ˆ๋ณ„๋กœ ํƒ€์ž…์ด ์กด์žฌํ•œ๋‹ค. (์ƒํ’ˆ, ์นดํ…Œ๊ณ ๋ฆฌ, ๊ธฐํš์ „, ๋ธŒ๋žœ๋“œ)
  • ์ƒ๋‹จ์˜ ํ•„ํ„ฐ ๋ฒ„ํŠผ์„ ํ†ตํ•ด ์ƒํ’ˆ์„ ํƒ€์ž…๋ณ„๋กœ ์กฐํšŒํ•ด ๋ณด์—ฌ์ค„ ์ˆ˜ ์žˆ์–ด์•ผ ํ•œ๋‹ค.
  • ๊ฐ ์ƒํ’ˆ์„ ํด๋ฆญํ•˜๋ฉด ํ•ด๋‹น ์ƒํ’ˆ์˜ ์‚ฌ์ง„์„ ๋ณด์—ฌ์ฃผ๋Š” ๋ชจ๋‹ฌ์„ ๋„์šธ ์ˆ˜ ์žˆ์–ด์•ผ ํ•œ๋‹ค.
  • ๊ฐ ์ƒํ’ˆ์— ์กด์žฌํ•˜๋Š” ๋ถ๋งˆํฌ ๋ฒ„ํŠผ์„ ๋ˆŒ๋Ÿฌ ์›ํ•˜๋Š” ์ƒํ’ˆ์„ ๋ถ๋งˆํฌ ํ•  ์ˆ˜ ์žˆ์–ด์•ผ ํ•œ๋‹ค.
  • ์ด๋ฏธ ๋ถ๋งˆํฌ ๋œ ์ƒํ’ˆ์˜ ๊ฒฝ์šฐ, ๋ถ๋งˆํฌ ๋ฒ„ํŠผ์— ํ‘œ์‹œ๋ฅผ ํ•ด์ฃผ์–ด์•ผ ํ•˜๋ฉฐ ๋‹ค์‹œ ํ•œ ๋ฒˆ ๋ถ๋งˆํฌ ๋ฒ„ํŠผ์„ ํด๋ฆญ ์‹œ ํ•ด๋‹น ์ƒํ’ˆ์„ ๋ถ๋งˆํฌ์—์„œ ์‚ญ์ œํ•œ๋‹ค.
  • ๋ถ๋งˆํฌ ๋ฒ„ํŠผ์„ ํด๋ฆญํ•˜์—ฌ ๋ถ๋งˆํฌ์— ์ถ”๊ฐ€ ํ•  ๋•Œ ๊ทธ๋ฆฌ๊ณ  ์‚ญ์ œํ•  ๋•Œ๋Š” ์‚ฌ์šฉ์ž์—๊ฒŒ ์•Œ๋ฆผ ํ† ์ŠคํŠธ๊ฐ€ ํ‘œ์‹œ๋˜์–ด์•ผ ํ•œ๋‹ค.

Bookmark page(๋ถ๋งˆํฌ ํŽ˜์ด์ง€)

  • path: /bookmark
  • ์‚ฌ์šฉ์ž๊ฐ€ ๋ถ๋งˆํฌ ํ•œ ์ƒํ’ˆ ๋“ค์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋Š” ํŽ˜์ด์ง€๋กœ ๋ฌดํ•œ ์Šคํฌ๋กค์ด ๊ฐ€๋Šฅํ•ด์•ผ ํ•œ๋‹ค.
  • ์ƒํ’ˆ๋ฆฌ์ŠคํŠธ ํŽ˜์ด์ง€์— ์กด์žฌํ•˜๋Š” ํ•„ํ„ฐ๋ง ๋ฒ„ํŠผ๊ณผ ๊ฐ™์€ ๋ฒ„ํŠผ์„ ์ด์šฉํ•ด ์ƒํ’ˆ์„ ํƒ€์ž…๋ณ„๋กœ ํ•„ํ„ฐํ•ด ๋ณด์—ฌ์ค„ ์ˆ˜ ์žˆ์–ด์•ผ ํ•œ๋‹ค.

ํด๋”๊ตฌ์กฐ

๐Ÿ“ฆCH4
โ”— ๐Ÿ“‚fe-sprint-coz-shopping
โ”ƒ โ”ฃ ๐Ÿ“‚.git
โ”ƒ โ”ฃ ๐Ÿ“‚.husky
โ”ƒ โ”ฃ ๐Ÿ“‚ node_modules
โ”ƒ โ”ฃ ๐Ÿ“‚src
โ”ƒ โ”ƒ โ”ฃ ๐Ÿ“‚api
โ”ƒ โ”ƒ โ”ƒ โ”— ๐Ÿ“œapi.jsx // api๋ถˆ๋Ÿฌ์˜ค๊ธฐ
โ”ƒ โ”ƒ โ”ฃ ๐Ÿ“‚assest
โ”ƒ โ”ƒ โ”ƒ โ”ฃ ๐Ÿ“œall.png
โ”ƒ โ”ƒ โ”ƒ โ”ฃ ๐Ÿ“œbrand.png
โ”ƒ โ”ƒ โ”ƒ โ”ฃ ๐Ÿ“œcategory.png
โ”ƒ โ”ƒ โ”ƒ โ”ฃ ๐Ÿ“œexhibition.png
โ”ƒ โ”ƒ โ”ƒ โ”ฃ ๐Ÿ“œlogo.png
โ”ƒ โ”ƒ โ”ƒ โ”— ๐Ÿ“œproduct.png
โ”ƒ โ”ƒ โ”ฃ ๐Ÿ“‚components
โ”ƒ โ”ƒ โ”ƒ โ”ฃ ๐Ÿ“œBookmark.jsx
โ”ƒ โ”ƒ โ”ƒ โ”ฃ ๐Ÿ“œCard.jsx
โ”ƒ โ”ƒ โ”ƒ โ”ฃ ๐Ÿ“œCardList.jsx
โ”ƒ โ”ƒ โ”ƒ โ”ฃ ๐Ÿ“œDescription.jsx
โ”ƒ โ”ƒ โ”ƒ โ”ฃ ๐Ÿ“œDropdown.jsx
โ”ƒ โ”ƒ โ”ƒ โ”ฃ ๐Ÿ“œFilter.jsx
โ”ƒ โ”ƒ โ”ƒ โ”ฃ ๐Ÿ“œFilterList.jsx
โ”ƒ โ”ƒ โ”ƒ โ”ฃ ๐Ÿ“œFooter.jsx
โ”ƒ โ”ƒ โ”ƒ โ”ฃ ๐Ÿ“œHeader.jsx
โ”ƒ โ”ƒ โ”ƒ โ”ฃ ๐Ÿ“œLoading.jsx
โ”ƒ โ”ƒ โ”ƒ โ”ฃ ๐Ÿ“œModal.jsx
โ”ƒ โ”ƒ โ”ƒ โ”ฃ ๐Ÿ“œPageTamplet.jsx // ๋ถ๋งˆํฌ ์ƒํ’ˆํŽ˜์ด์ง€ ์ปดํฌ๋„ŒํŠธ
โ”ƒ โ”ƒ โ”ƒ โ”ฃ ๐Ÿ“œToast.jsx
โ”ƒ โ”ƒ โ”ƒ โ”ฃ ๐Ÿ“œToastContainer.jsx
โ”ƒ โ”ƒ โ”ƒ โ”— ๐Ÿ“œXmark.jsx
โ”ƒ โ”ƒ โ”ฃ ๐Ÿ“‚hook
โ”ƒ โ”ƒ โ”ƒ โ”ฃ ๐Ÿ“œuseApi.jsx
โ”ƒ โ”ƒ โ”ƒ โ”— ๐Ÿ“œuseClick.jsx //ํ—ค๋”์˜ ํ–„๋ฒ„๊ฑฐ ์•„์ด์ฝ˜ click hook
โ”ƒ โ”ƒ โ”ฃ ๐Ÿ“‚pages
โ”ƒ โ”ƒ โ”ƒ โ”ฃ ๐Ÿ“œBookmark.jsx
โ”ƒ โ”ƒ โ”ƒ โ”ฃ ๐Ÿ“œHome.jsx
โ”ƒ โ”ƒ โ”ƒ โ”ฃ ๐Ÿ“œNotFound.jsx
โ”ƒ โ”ƒ โ”ƒ โ”— ๐Ÿ“œProductLists.jsx
โ”ƒ โ”ƒ โ”ฃ ๐Ÿ“‚redux //redux reducer, store,action๋“ค์„ ์ •๋ฆฌ
โ”ƒ โ”ƒ โ”ƒ โ”ฃ ๐Ÿ“‚action
โ”ƒ โ”ƒ โ”ƒ โ”ƒ โ”— ๐Ÿ“œactions.js
โ”ƒ โ”ƒ โ”ƒ โ”— ๐Ÿ“‚reducer
โ”ƒ โ”ƒ โ”ƒ โ”ƒ โ”ฃ ๐Ÿ“œhambegeReducer.js //ํ—ค๋”์˜ ํ–„๋ฒ„๊ฑฐ ์•„์ด์ฝ˜ ๊ด€๋ จ reducer
โ”ƒ โ”ƒ โ”ƒ โ”ƒ โ”ฃ ๐Ÿ“œmodalReducer.js //๋ชจ๋‹ฌ ๊ด€๋ จ reducer
โ”ƒ โ”ƒ โ”ƒ โ”ƒ โ”ฃ ๐Ÿ“œreducer.js // bookmark๊ด€๋ จ reducer
โ”ƒ โ”ƒ โ”ƒ โ”ƒ โ”ฃ ๐Ÿ“œrootReducer.js // Root reducer
โ”ƒ โ”ƒ โ”ƒ โ”ƒ โ”ฃ ๐Ÿ“œstore.js
โ”ƒ โ”ƒ โ”ƒ โ”ƒ โ”— ๐Ÿ“œtoastReducer.js // Toast UI๊ด€๋ จ reducer
โ”ƒ โ”ƒ โ”ฃ ๐Ÿ“‚routers
โ”ƒ โ”ƒ โ”ƒ โ”— ๐Ÿ“œRouters.jsx
โ”ƒ โ”ƒ โ”ฃ ๐Ÿ“‚util
โ”ƒ โ”ƒ โ”ƒ โ”— ๐Ÿ“œgetRandomForSlice.js
โ”ƒ โ”ƒ โ”ฃ ๐Ÿ“œApp.jsx
โ”ƒ โ”ƒ โ”ฃ ๐Ÿ“œGlobalStyle.jsx
โ”ƒ โ”ƒ โ”ฃ ๐Ÿ“œmain.jsx
โ”ƒ โ”ƒ โ”— ๐Ÿ“œtheme.js
โ”ƒ โ”ฃ ๐Ÿ“œ.eslintrc.cjs
โ”ƒ โ”ฃ ๐Ÿ“œ.gitignore
โ”ƒ โ”ฃ ๐Ÿ“œ.prettierrc
โ”ƒ โ”ฃ ๐Ÿ“œindex.html
โ”ƒ โ”ฃ ๐Ÿ“œpackage-lock.json
โ”ƒ โ”ฃ ๐Ÿ“œpackage.json
โ”ƒ โ”ฃ ๐Ÿ“œREADME.md
โ”ƒ โ”— ๐Ÿ“œvite.config.js

์ตœ์ข… ์™„์„ฑ

Vite.+.React.6.mp4

์ง„ํ–‰ ๊ณผ์ • ์ •๋ฆฌ

1. Router ์„ค์ •

  • ๊ธฐ์กด CRA๋กœ ํ˜•์„ฑํ•œ react ํ…œํ”Œ๋ฆฟ์—์„œ๋Š” BrowserRouter๋กœ ๊ฐ์‹ธ๋Š” ํ˜•ํƒœ๋กœ ์ž‘์—…ํ•˜์˜€์„ ๋•Œ ์ •์ƒ์ ์œผ๋กœ ์ถœ๋ ฅ์ด ๋˜์—ˆ์ง€๋งŒ, vite ํ…œํ”Œ๋ฆฟ์—์„œ๋Š” ์ž‘๋™์ด ๋˜์ง€ ์•Š์•„์„œ ๊ณต์‹ ํ™ˆํŽ˜์ด์ง€ ๋“€ํ† ๋ฆฌ์–ผ์„ ์ฐธ๊ณ ํ•˜๋ฉด์„œ ๋‹ค์‹œ ์ง„ํ–‰ํ•˜์˜€์Šต๋‹ˆ๋‹ค.
  • ๊ณต์‹ ๋ธ”๋กœ๊ทธ
    • 4๊ฐœ์˜ ํŽ˜์ด์ง€๋ฅผ ๋งŒ๋“ค์–ด์„œ ๊ธฐ๋ณธ router ๊ตฌ์„ฑ Home, ProductList, Bookmark, NotFound
    • BrowserRouter์™€ createBrowserRouter์˜ ์ฐจ์ด์— ๋Œ€ํ•ด์„œ ์ดํ•ดํ•  ์ˆ˜ ์žˆ์—ˆ๋‹ค. createBrowserRouter์—์„œ๋Š” DataRoiter๋ฅผ ์ œ๊ณตํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋” ๋งŽ์€ ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์—ˆ๋‹ค. (ex. data APIs) ๋”ฐ๋ผ์„œ NotFound ํŽ˜์ด์ง€์—์„œ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ๋Š” useRouteError ํ›…์€ createBrowserRouter์—์„œ๋งŒ ์‚ฌ์šฉ๊ฐ€๋Šฅํ•˜์˜€๋‹ค. ๋งํฌ
  • App์„ ์ ˆ๋Œ€๊ฒฝ๋กœ๋กœ ์„ค์ •ํ•˜์—ฌ Router ์ž‘์—…์„ ์ง„ํ–‰ํ•˜์˜€์Šต๋‹ˆ๋‹ค. ์ดˆ๊ธฐ์— createBrowserRouter์—์„œ ์ œ๊ณตํ•˜๋Š” DataAPIs๊ฐ€ ๋งค์šฐ ๋งค๋ ฅ์ ์œผ๋กœ ๋‹ค๊ฐ€์™”์Šต๋‹ˆ๋‹ค. ํŠนํžˆ DataAPIs๊ฐ€ ์ œ๊ณตํ•˜๋Š” ์—ฌ๋Ÿฌ ํ›…์ค‘์—์„œ useRouteError๊ฐ€ ๋งค๋ ฅ์ ์ด์—ˆ์Šต๋‹ˆ๋‹ค. ์„ค์ •์— ๋”ฐ๋ผ์„œ router ์• ๋Ÿฌ ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ, ๋‹ค๋ฅธ ์• ๋Ÿฌ๋„ ์บก์ณํ•ด์„œ ํŽ˜์ด์ง€๋ฅผ ์ž๋™์œผ๋กœ ์ „ํ™˜ ํ•ด์ฃผ๋Š” ๊ธฐ๋Šฅ์ด ์ธ์ƒ๊นŠ์—ˆ์Šต๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ APU๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด์„œ createBrowserRouter๋ฅผ ์ ์šฉํ•˜์˜€์Šต๋‹ˆ๋‹ค.
  • ์—ฌ๊ธฐ์„œ ๋ฌธ์ œ๋Š” createBrowserRouter๋ฅผ ์‚ฌ์šฉํ•œ ๊ฒฝ์šฐ Outlet๊ณผ ํ•จ๊ป˜ ์‚ฌ์šฉ๋˜๋Š”๋ฐ, ์ €๋Š” ๊ฐ๊ฐ์˜ ํŽ˜์ด์ง€์— prop์ „๋‹ฌ์„ ํ•˜๊ณ  ์‹ถ์–ด์„œ Routes์™€ Route๋ฅผ ํ™œ์šฉํ–ˆ์Šต๋‹ˆ๋‹ค.
// ./routers/Routers.jsx
import { createBrowserRouter } from "react-router-dom";
import NotFound from "../pages/NotFound";
import ProductLists from "../pages/ProductLists";
import Bookmark from "../pages/Bookmark";
import App from "../App";
import Home from "../pages/Home";

const router = createBrowserRouter([
  {
    path: "/",
    element: <App />,
    children: [
      {
        path: "/",
        element: <Home />,
      },
      {
        path: "/products/list",
        element: <ProductLists />,
      },
      {
        path: "/bookmark",
        element: <Bookmark />,
      },
    ],
    errorElement: <NotFound />,
  },
]);

export default router;
// ./App.jsx
import { Routes, Route } from "react-router-dom";
import Header from "./components/Header";
import Footer from "./components/Footer";
import Home from "./pages/Home";
import ProductLists from "./pages/ProductLists";
import Bookmark from "./pages/Bookmark";
import useHeaderClick from "./hook/useHeaderClick";
import NotFound from "./pages/NotFound";
import useApi from "./hook/useApi";
import { useDispatch } from "react-redux";
import { dispatchData } from "./redux/action/actions";
import { useEffect, useState } from "react";
import Toast from "./components/Toast";

function App() {
  // header ํด๋ฆญ ์ ์šฉํ•˜๊ธฐ
  const { click, setClick, handleClick } = useHeaderClick();
  //api ๋ถˆ๋Ÿฌ์˜ค๊ธฐ
  const { data, isLoading } = useApi();

  //Toast ์กฐ์ •
  const [toast, setToast] = useState(false);
  const [toastBookmar, setToastBookmark] = useState(false);

  useEffect(() => {
    const id = setTimeout(() => {
      setToast(false);
    }, 1000);
    return () => {
      clearTimeout(id);
    };
  }, [toast, toastBookmar]);
  //query ๋ฐ์ดํ„ฐ redux์— ์ €์žฅํ•˜๊ธฐ
  const dispatch = useDispatch();
  useEffect(() => {
    dispatch(dispatchData(data));
  }, []);

  return (
    <>
      <Header click={click} setClick={setClick} handleClick={handleClick} />
      <Routes>
        <Route
          path="*"
          element={
            <Home
              handleClick={handleClick}
              isLoading={isLoading}
              setToast={setToast}
              setToastBookmark={setToastBookmark}
            />
          }
        />
        <Route
          path="/products/list"
          element={
            <ProductLists
              handleClick={handleClick}
              setToast={setToast}
              setToastBookmark={setToastBookmark}
            />
          }
        />
        <Route
          path="/bookmark"
          element={
            <Bookmark
              handleClick={handleClick}
              setToast={setToast}
              setToastBookmark={setToastBookmark}
            />
          }
        />
        <Route path="/*" element={<NotFound />} />
      </Routes>
      {toast && <Toast toastBookmar={toastBookmar} />}
      <Footer handleClick={handleClick} />
    </>
  );
}

export default App;

๐Ÿ’ฃ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์„ค์ • ํ•˜์˜€์„ ๋•Œ, ์ฝ˜์†”์—์„œ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๊ฒฝ๊ณ ์ฐฝ์„ ๋ณด์—ฌ์ง€๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

history.ts:487 You rendered descendant <Routes> (or called `useRoutes()`) at "/" (under <Route path="/">) but the parent route path has no trailing "*". This means if you navigate deeper, the parent won't match anymore and therefore the child routes will never render.

Please change the parent <Route path="/"> to <Route path="*">.
  • ์ œ์‹œํ•œ ํ•ด๊ฒฐ๋ฐฉ๋ฒ• ์ฒ˜๋Ÿผ path๋ฅผ ์ˆ˜์ •ํ•œ ์ƒํƒœ์—์„œ๋„ ์ด์™€ ๊ฐ™์€ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. createBrowserRouter์™€ Routes๋ฅผ ํ˜ผํ•ฉํ•ด์„œ ์‚ฌ์šฉํ•œ ๋ฌธ์ œ ์ธ๋“ฏ ํ•˜์—ฌ, ํ•˜๋‚˜์˜ ๋ฐฉ์‹๋งŒ ์‚ฌ์šฉํ•˜๋„๋ก ์ˆ˜์ •์ด ํ•„์š”ํ•  ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

2. ๊ธฐ๋ณธ CSS ์„ค์ •

  • styledComponent์˜ ์ „์—ญ ์Šคํƒ€์ผ ์„ค์ •ํ•˜๊ธฐ, createGlobalStyle๋ฅผ ํ™œ์šฉํ–ˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  reset css๋ฅผ ์ ์šฉํ–ˆ์Šต๋‹ˆ๋‹ค. reset css
  • styledComponent Theme์„ ํ™œ์šฉํ•ด์„œ ๊ธฐ๋ณธ์ ์œผ๋กœ ์‚ฌ์šฉํ•˜๋Š” ํฐํŠธ์˜ ํฌ๊ธฐ, ๊ฐ margin ๊ฐ’, color๋ฅผ ์„ค์ •ํ–ˆ์Šต๋‹ˆ๋‹ค.
  • reset css๋กœ ์ธํ•ด ๋ณ€ํ™”๋œ NotFound Page์˜ css๋ฅผ ์ˆ˜์ •ํ–ˆ์Šต๋‹ˆ๋‹ค.

3. ํ—ค๋” ์ปดํฌ๋„ŒํŠธ ๋งŒ๋“ค๊ธฐ

  • ํ—ค๋” ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ž‘์„ฑํ–ˆ์Šต๋‹ˆ๋‹ค. ์ตœ๋Œ€ํ•œ ํ”ผ๊ทธ๋งˆ์—์„œ ์ž‘์„ฑํ•œ ๋””์ž์ธ๊ณผ ์œ ์‚ฌํ•˜๊ฒŒ ๋งŒ๋“ค๋„๋ก ๋…ธ๋ ฅํ–ˆ์Šต๋‹ˆ๋‹ค.
  • icon ๊ฐ™์€ ๊ฒฝ์šฐ svg ์™€ fontawsome ์•„์ด์ฝ˜์„ ํ•จ๊ป˜ ํ™œ์šฉํ•ด์„œ icon์„ ํ™œ์šฉํ–ˆ์Šต๋‹ˆ๋‹ค.
  • ๋งํ’์„  ๊ฐ™์€ ๊ฒฝ์šฐ๋Š” ๋‹ค์Œ ๋ธ”๋กœ๊ทธ๋ฅผ ์ฐธ๊ณ ํ–ˆ์Šต๋‹ˆ๋‹ค. ๋งํฌ
  • ํ—ค๋” ์ปดํฌ๋„ŒํŠธ์˜ ํ–„๋ฒ„๊ฑฐ๋ฅผ ํด๋ฆญํ•˜๋ฉด Dropdown ํ˜•ํƒœ๋กœ ๋ฉ”๋‰ด๊ฐ€ ๋“ฑ์žฅํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ด๋•Œ ํ–„๋ฒ„๊ฑฐ ๋ฒ„ํŠผ์ด ํด๋ฆญ ๋˜์–ด์•ผ ํ–„๋ฒ„๊ฑฐ๊ฐ€ ์‚ฌ๋ผ์ง€๊ฒŒ ๋˜๋Š” ํ˜•ํƒœ๊ฐ€ ๋ถˆํŽธํ•˜๋‹ค๊ณ  ๋А๊ผˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ ์ „์—ญ์—์„œ state๋ฅผ ๊ฐ์ง€ํ•ด์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ์ˆ˜์ •ํ–ˆ์Šต๋‹ˆ๋‹ค. component hook useHeaderClick์„ ๋งŒ๋“ค์–ด์„œ App ์ƒ์—์„œ state๋ฅผ ๊ด€๋ฆฌํ•˜๋„๋ก ํ•˜์˜€์Šต๋‹ˆ๋‹ค. ํ–„๋ฒ„๊ฑฐ ๋ฒ„ํŠผ์ด ํด๋ฆญ ๋˜์–ด DropDown ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋ณด์ด๋Š” ์ƒํƒœ๋ผ๋ฉด, ์–ด๋–ค ํ™”๋ฉด์„ ํด๋ฆญํ•ด๋„ ๋‹ค์‹œ ๋‹ซํžˆ๋„๋ก ๊ตฌ์„ฑํ–ˆ์Šต๋‹ˆ๋‹ค.

4. Footer ์ปดํฌ๋„ŒํŠธ ๋งŒ๋“ค๊ธฐ

  • FooterComponent ๊ตฌํ˜„.

5. ๋ฉ”์ธ ํŽ˜์ด์ง€ ๊ตฌํ˜„ํ•˜๊ธฐ

5-1. API ๊ฐ€์ง€๊ณ  ์˜ค๊ธฐ

  • react-query๋ฅผ ํ™œ์šฉํ•ด์„œ API ๋ฐ์ดํ„ฐ๋ฅผ ๋ถˆ๋Ÿฌ์™”์Šต๋‹ˆ๋‹ค.
  • ์ดˆ๊ธฐ์—๋Š” api ํ•จ์ˆ˜๋งŒ์„ ๋”ฐ๋กœ ๋ถ„๋ฆฌํ•˜์˜€๋Š”๋ฐ, ๋ฐ์ดํ„ฐ๋ฅผ ๋ถˆ๋Ÿฌ์™€์„œ ๊ฒฐ๊ณผ๋ฅผ ๋ฐ›๋Š” hook ๋˜ํ•œ ๋ถ„๋ฆฌํ•˜๋Š” ๊ฒƒ์ด ์ข‹์„ ๋“ฏ ํ•˜์—ฌ useApi component hook์„ ๋งŒ๋“ค์—ˆ์Šต๋‹ˆ๋‹ค.

5-2. Card ์ปดํฌ๋„ŒํŠธ ๋งŒ๋“ค๊ธฐ

  • Card Component๋ฅผ ๋งŒ๋“ค์—ˆ์Šต๋‹ˆ๋‹ค. API์˜ ํƒ€์ž… ์†์„ฑ์— ๋”ฐ๋ผ ์„ค๋ช… ๋ชจ์–‘์— ์ฐจ์ด๊ฐ€ ์žˆ์–ด์„œ Description.jsx ์ปดํฌ๋„ŒํŠธ์—์„œ ๋ถ„๊ธฐ ์ฒ˜๋ฆฌ๋ฅผ ํ•˜์—ฌ ๋ Œ๋”๋งํ•˜๋„๋ก ์ž‘์„ฑํ–ˆ์Šต๋‹ˆ๋‹ค.

  • ๊ฐ€๊ฒฉ๊ณผ follower ๊ฐ™์€ ๊ฒฝ์šฐ๋Š” ์‰ผํ‘œ ์ฒ˜๋ฆฌ๋ฅผ ํ•ด์ฃผ์–ด์•ผ ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์ •๊ทœํ‘œํ˜„์‹์„ ํ™œ์šฉํ–ˆ์Šต๋‹ˆ๋‹ค. toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',')

5-3. ๋ชจ๋‹ฌ ๋งŒ๋“ค๊ธฐ

  • ๋ชจ๋‹ฌ ๋งŒ๋“ค๊ธฐ๋Š” ์˜ˆ์ „์— ๋งŒ๋“  Modal component๋ฅผ ์ฐธ๊ณ ํ–ˆ์Šต๋‹ˆ๋‹ค. Modal Link

6. redux๋ฅผ ํ†ตํ•œ ์ƒํƒœ๊ด€๋ฆฌ

6.1 ์ฒญ์‚ฌ์ง„ ๊ตฌ์ƒํ•˜๊ธฐ

  • ์šฐ์„  rtk query๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ณ , react query๋ฅผ ํ™œ์šฉํ•˜๊ณ ์ž ํ•œ๋‹ค. ๋”ฐ๋ผ์„œ react query๋กœ ๋ฐ›์•„์˜จ ๋ฐ์ดํ„ฐ๋ฅผ redux์˜ ๋ฐ์ดํ„ฐ๋กœ ๊ตฌ์„ฑํ•˜๋Š” action์„ ๋งŒ๋“ค์–ด์•ผ ํ•œ๋‹ค. ๋”๋ถˆ์–ด data๋ฅผ ๋ฐ›์•„ ์˜ฌ ๋•Œ, ๋ฐ์ดํ„ฐ ๋‚ด์—์„œ bookmark์— ๊ด€ํ•œ ์ •๋ณด๊ฐ€ ์—†๊ธฐ ๋•Œ๋ฌธ์—, bookmark ํ”„๋กœํผํ‹ฐ๋ฅผ ์ถ”๊ฐ€ํ•ด์ฃผ์–ด์•ผ ํ•œ๋‹ค.

  • ๋จผ์ € redux-toolkit์„ ํ™œ์šฉํ•ด์„œ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜์˜€๋‹ค. ์ด 3๊ฐœ์˜ action์„ ์ˆ˜ํ–‰ํ•˜๋„๋ก ์ž‘์„ฑํ•˜์˜€๋‹ค. bookmark ์ถ”๊ฐ€ ๊ธฐ๋Šฅ๊ณผ bookmark ํ•ด์ œ ๊ธฐ๋Šฅ, react-query์—์„œ ๋ฐ›์•„์˜จ ๋ฐ์ดํ„ฐ๋ฅผ ์ดˆ๊ธฐ ๋ฐ์ดํ„ฐ๋กœ ์„ค์ •ํ•˜๋Š” ๊ฒƒ์ด๋‹ค.

  • ์ด๋•Œ ์–ด๋””์„œ react query๋กœ ๋ฐ›์•„์˜จ ๋ฐ์ดํ„ฐ๋ฅผ ์ฒ˜๋ฆฌํ•ด์„œ redux๋กœ ๋ณด๋‚ด์ฃผ๋Š”๊ฐ€๊ฐ€ ๋ฌธ์ œ ์˜€๋‹ค. ์ด๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด ๊ฐ€์žฅ ์ตœ์ƒ์œ„์ธ App์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ›์•„์˜ค๊ณ  ์ด๋ฅผ dispatchํ•˜๋„๋ก ๊ตฌ์ƒํ•˜์˜€๋‹ค.

6.2 ์ž‘์„ฑ ์ค‘ ๋งˆ์ฃผ์นœ ๋ฌธ์ œ์ 

  • bookmark ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋งŒ๋“ค๊ณ , useEffect๋ฅผ ํ™œ์šฉํ•ด์„œ App.jsx์—์„œ ์ตœ์ดˆ๋กœ API ๋ฐ์ดํ„ฐ๋ฅผ redux๋กœ ๋ณด๋‚ด๋„๋ก ์„ค์ •ํ•˜์˜€๋‹ค. ์ด๋•Œ ๋ฐœ์ƒํ•˜๋Š” ๋ฌธ์ œ๋Š”, ํŽ˜์ด์ง€๋ฅผ ์ƒˆ๋กœ๊ณ ์นจ ํ•˜์˜€์„๋•Œ, react query์—์„œ cashe๋œ ๋ฐ์ดํ„ฐ๋ฅผ ํ™œ์šฉํ•˜๊ธฐ์— ์ƒˆ๋กญ๊ฒŒ ๋ณด๋‚ด๋Š” ๋ฐ์ดํ„ฐ๊ฐ€ ์—†๋‹ค๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์—ˆ๋‹ค. ๋˜ํ•œ ๋งค๋ฒˆ ์ƒˆ๋กœ ๊ณ ์นจ ํ• ๋•Œ๋งˆ๋‹ค ๋ฐ์ดํ„ฐ๊ฐ€ ์ดˆ๊ธฐํ™” ๋˜๊ธฐ ๋•Œ๋ฌธ์— ๋ถ๋งˆํฌ ๊ธฐ๋Šฅ์ด ์†Œ์šฉ์ด ์—†์—ˆ๋‹ค. ์ด๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด localstorage๋ฅผ ํ™œ์šฉํ–ˆ๋‹ค.

6.3 redux-persist ์ ์šฉํ•˜๊ธฐ ์ฐธ๊ณ 

  • redux ๊ณผ๋ จ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์ค‘์—์„œ local storage๋ฅผ ์ ์šฉํ•ด์ฃผ๋Š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•ด์„œ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ–ˆ๋‹ค. ์ด๋•Œ redux-toolkit์œผ๋กœ ์ž‘์„ฑํ•œ ์ฝ”๋“œ๋ฅผ ์ ์šฉํ•˜๋Š” ๊ณผ์ •์—์„œ ์• ๋Ÿฌ๊ฐ€ ์ง€์†์ ์œผ๋กœ ๋ฐœ์ƒํ•ด, toolkit์„ ํ™œ์šฉํ•˜์ง€ ์•Š๊ณ  ์ผ๋ฐ˜ redux์™€ react-redux๋ฅผ ํ™œ์šฉํ•˜๋Š” ์ฝ”๋“œ๋กœ ์ˆ˜์ •ํ•˜์˜€๋‹ค.(์•„์ง toolkit์— ์ต์ˆ™ํ•˜์ง€ ์•Š์•„ ์–ด๋””์„œ ๋ฐœ์ƒํ•˜๋Š” ์˜ค๋ฅ˜์ธ์ง€ ์ฐพ์„ ์ˆ˜ ์—†์–ด ์ฝ”๋“œ๋ฅผ ์ „์ฒด์ ์œผ๋กœ ์ˆ˜์ •ํ–ˆ๋‹ค.!) ์ถ”๊ฐ€์ ์œผ๋กœ localStorage์— ์ €์žฅ๋œ ๋ฐ์ดํ„ฐ๊ฐ€ ์žˆ๋‹ค๋ฉด, react-query ๋ฐ์ดํ„ฐ๋ฅผ ํ™œ์šฉํ•˜์ง€ ์•Š๊ณ , localStorage ๋ฐ์ดํ„ฐ๋ฅผ ํ™œ์šฉํ•˜๋„๋ก initialvalue๋ฅผ ์ˆ˜์ •ํ•˜์˜€๋‹ค.

  • ์ •์ƒ ์ž‘๋™์„ ํ…Œ์ŠคํŠธ ํ•ด๋ณด๋‹ˆ ์ž‘๋™์€ ์ •์ƒ์ ์œผ๋กœ ํ•˜์˜€๋‹ค. ๋‹ค๋งŒ localStorage๋ฅผ ์ ์šฉํ•˜๋‹ˆ ๋ฉ”์ธ ํŽ˜์ด์ง€์˜ ์ƒํ’ˆํŽ˜์ด์ง€๊ฐ€ ๊ณ ์ •๋œ ์ƒํ’ˆ๋งŒ ๋ณด์—ฌ์ฃผ๊ฒŒ ๋˜์–ด ์ด๋ฅผ ์ˆ˜์ •ํ•˜๊ธฐ ์œ„ํ•ด random์œผ๋กœ ์ˆซ์ž๋ฅผ ๋ฝ‘๋Š” ํ•จ์ˆ˜๋ฅผ ์ž‘์„ฑํ–ˆ๋‹ค.

  • redux์—์„œ actions์„ ๋ฐ›๊ณ  reducer์„ ํ•˜๋Š” ๊ณผ์ •์—์„œ store์— ์ €์žฅ๋œ ๋ฐ์ดํ„ฐ๊ฐ€ ๋ณ€๊ฒฝ๋˜์–ด ํŠน์ • ๊ณผ์ •์—์„œ ์• ๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•˜๋Š” ๊ฒƒ์„ ํ™•์ธํ–ˆ์Šต๋‹ˆ๋‹ค. ์ด๋ฅผ ์ˆ˜์ •ํ•˜๊ธฐ ์œ„ํ•ด์„œ redux-persist๊ฐ€ ์ €์žฅํ•˜๋Š” ๋ฐ์ดํ„ฐ ํ˜•ํƒœ๋กœ state์˜ ๋ฐ์ดํ„ฐ ํ˜•ํƒœ๋ฅผ ์ˆ˜์ •ํ•˜์˜€์œผ๋ฉฐ, ๊ฐ๊ฐ์˜ action์ด ๋ฐ˜ํ™˜ํ•˜๋Š” ๋ฐ์ดํ„ฐ์˜ ํ˜•ํƒœ๋„ ์ผ์น˜์‹œ์ผฐ์Šต๋‹ˆ๋‹ค.

7. filter Component

  • filter ๋ฒ„ํŠผ์€ ๊ณ ์ •๋œ ํ˜•ํƒœ์ž…๋‹ˆ๋‹ค. ๋ฐ์ดํ„ฐ๊ฐ€ ๋ณ€ํ™”๋  ์ผ์ด ์—†๊ธฐ ๋•Œ๋ฌธ์—, index๋กœ key ๊ฐ’์„ ์ฃผ์–ด๋„ ๋ฌธ์ œ๊ฐ€ ์—†์—ˆ์Šต๋‹ˆ๋‹ค.
  • ๊ฐ๊ฐ์˜ ๋ฒ„ํŠผ์— ์‚ฌ์šฉํ•  ์ด๋ฏธ์ง€๋ฅผ ๋ฐฐ์—ด ํ˜•ํƒœ๋กœ ๊ฐ€์ง€๊ณ  ์˜ค๊ณ , ๊ฐ ๋ฒ„ํŠผ์˜ ์ด๋ฆ„๋˜ํ•œ ๋ฐฐ์—ด๋กœ ์ •๋ฆฌํ–ˆ์Šต๋‹ˆ๋‹ค.
  • ๋ฒ„ํŠผ์ด ํด๋ฆญ ๋˜์—ˆ์„ ๋•Œ, ๋ฒ„ํŠผ์„ ๊ฐ•์กฐํ•˜๊ธฐ ์œ„ํ•œ css ์ˆ˜์ •์ด ํ•„์š”ํ–ˆ์Šต๋‹ˆ๋‹ค. ์ด๋ฅผ ์œ„ํ•ด numState๋ฅผ useState๋ฅผ ํ†ตํ•ด state๋กœ ๋งŒ๋“ค์—ˆ์Šต๋‹ˆ๋‹ค. ๋ฒ„ํŠผ์ด ํด๋ฆญ๋˜์—ˆ์„ ๋–„, ๊ฐ ๋ฒ„ํŠผ์˜ index์— ๋งž์ถ”์–ด numState์˜ ๊ฐ’์„ index์˜ ๊ฐ’์œผ๋กœ ์ˆ˜์ •ํ–ˆ์Šต๋‹ˆ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด์„œ index์™€ numState์˜ ๊ฐ’์ด ๊ฐ™์„๋•Œ, ํ•ด๋‹น ๋ฒ„ํŠผ์ด ํด๋ฆญ ๋˜์—ˆ๋‹ค๋Š” ํ‘œ์‹œ๋ฅผ ํ•  ์ˆ˜ ์žˆ๋„๋ก ์ž‘์„ฑํ•˜์˜€์Šต๋‹ˆ๋‹ค.

8. ๋ถ๋งˆํฌ ํŽ˜์ด์ง€ & ์ƒํ’ˆํŽ˜์ด์ง€

  • ๋‘ ํŽ˜์ด์ง€์˜ ํ˜•ํƒœ๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ๋ณด์—ฌ์ฃผ๋Š” ๋ฐฉ์‹๋งŒ ๋‹ค๋ฅผ ๋ฟ ๋ชจ๋‘ ๋˜‘๊ฐ™์ด ์ž‘์„ฑํ–ˆ์Šต๋‹ˆ๋‹ค. ๋‹ค๋งŒ ๊ฐ™์€ ์ฝ”๋“œ๊ฐ€ ๋„ˆ๋ฌด ๋˜‘๊ฐ™์ด ๋ฐ˜๋ณต๋˜์–ด ๋ชจ๋“  ๊ธฐ๋Šฅ์„ ๊ตฌํ˜„ํ›„์— ์ฝ”๋“œ ๋ฆฌํŽ™ํ† ๋ง์„ ํ•ด์•ผ ํ•  ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.
  • ๋˜ํ•œ numState์˜ ์ƒํƒœ์— ๋”ฐ๋ผ ํ™”๋ฉด์— ๋ฟŒ๋ ค์ค„ ๋ฐ์ดํ„ฐ๋ฅผ ์ถ”๋ ธ์Šต๋‹ˆ๋‹ค. ์ด ๊ณผ์ •์—์„œ๋„ ๊ฐ™์€ ์ฝ”๋“œ๋ฅผ 5๋ฒˆ์ด๋‚˜ ๋ฐ˜๋ณตํ•ด์„œ ์—ญ์‹œ ์ดํ›„์— ๋ฆฌํŽ™ํ† ๋ง์ด ํ•„์š”ํ•  ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

9. Toast UI ํŽ˜์ด์ง€ ๊ตฌ์„ฑ

  • ์ฒ˜์Œ ์ƒ๊ฐํ•œ ๋ฐฉ์‹์€ redux๋ฅผ ํ†ตํ•œ toastUI ๊ตฌ์„ฑ์ด์—ˆ์Šต๋‹ˆ๋‹ค. ๋งˆ์นจ CH3 redux๋ฅผ ํ•™์Šตํ•  ๋‹น์‹œ์— ์˜ˆ์‹œ ์ฝ”๋“œ์— redux middleware ์ค‘ ํ•˜๋‚˜์ธ thunk๋ฅผ ํ™œ์šฉํ•˜์—ฌ toast ui์ž‘์—…์„ ํ•œ ์ฝ”๋“œ๊ฐ€ ์žˆ์–ด์„œ ์ด๋ฅผ ๋ฆฌํŽ™ํ† ๋ง ํ•˜์—ฌ ์ž‘์—…์„ ํ•˜๋ฉด ๋  ๊ฒƒ ๊ฐ™์•˜์Šต๋‹ˆ๋‹ค.
  • ํ•˜์ง€๋งŒ redux๋ฅผ ํ™œ์šฉํ•˜๊ธฐ ์œ„ํ•ด์„œ ํฌ๊ฒŒ ๋‘ ๊ฐ€์ง€ ๋ฌธ์ œ๊ฐ€ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค. ์ฒซ ๋ฒˆ์งธ๋กœ ํ•˜๋‚˜์˜ ๊ธฐ๋Šฅ ๊ตฌํ˜„์„ ์œ„ํ•ด์„œ ์ƒˆ๋กœ์šด reducer๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ์ „์—ญ ๋ณ€์ˆ˜๋กœ ์ƒํƒœ๋ฅผ ๊ด€๋ฆฌํ•˜๋Š”๊ฒŒ ๊ณผ์—ฐ ๋งž์„๊นŒ? ๋ผ๋Š” ์˜๋ฌธ์„ ๊ฐ€์ง€๊ฒŒ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ํ•˜๋‚˜์˜ ๊ธฐ๋Šฅ์„ ์œ„ํ•ด ๊ตฌํ˜„ํ•  ๋ถ€๊ฐ€์ ์ธ ์ฝ”๋“œ๊ฐ€ ๋„ˆ๋ฌด๋‚˜ ๋งŽ์•„์ง„๋‹ค๊ณ  ์ƒ๊ฐํ•˜์˜€์Šต๋‹ˆ๋‹ค. ๋˜ํ•œ ํ˜„์žฌ ๊ตฌํ˜„ํ•˜๋Š” APP์˜ ๊ทœ๋ชจ๊ฐ€ ๊ทธ๋ฆฌ ํฌ์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— ๊ตณ์ด toast๋ฅผ ๋น„๋™๊ธฐ๋กœ ์ฒ˜๋ฆฌํ•ด์•ผ ํ•  ํ•„์š”๋ฅผ ๋А๋ผ์ง€ ๋ชปํ–ˆ์Šต๋‹ˆ๋‹ค.
  • ๊ทธ๋ž˜์„œ useState์™€ useEffect๋ฅผ ํ™œ์šฉํ•˜์—ฌ Toast UI๋ฅผ ์ž‘์—…ํ•˜๋„๋ก ํ•˜์˜€์Šต๋‹ˆ๋‹ค.
  • ์ฒ˜์Œ์—๋Š” Bookmark ์ปดํฌ๋„ŒํŠธ์— Toast ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ž‘์„ฑํ•˜์—ฌ ์ž‘์—…์„ ํ•˜๋ ค ํ–ˆ์Šต๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ์ด๋•Œ ๊ฐ Card ์ปดํฌ๋„ŒํŠธ ๋ณ„๋กœ Toast ์ปดํฌ๋„ŒํŠธ์˜ ์œ„์น˜๊ฐ€ ์žกํ˜€์ง€๊ณ  ์ตœ๋Œ€ 100๊ฐœ์˜ Toast ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์ƒ์„ฑ๋œ๋‹ค๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค. ์ด๋Š” ๊ณ ์ •๋œ ํ•˜๋‚˜์˜ position์„ ์žก๋Š” ๊ฒƒ์— ๋ฌธ์ œ๊ฐ€ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ Toast ์ปดํฌ๋„ŒํŠธ์˜ ์œ„์น˜๋ฅผ APP์— ์œ„์น˜ํ•˜์—ฌ ํ•˜๋‚˜์˜ ์ปดํฌ๋„ŒํŠธ ๋งŒ์„ state ์ฒ˜๋ฆฌ๋ฅผ ํ†ตํ•ด ๋ถˆ๋Ÿฌ์˜ค๋„๋ก ํ•˜์˜€์Šต๋‹ˆ๋‹ค.
  • ์ด ๋‘๊ฐœ์˜ state๋ฅผ ํ™œ์šฉํ•˜์˜€์Šต๋‹ˆ๋‹ค. toastBookmark์™€ toast state๋ฅผ ํ™œ์šฉํ•˜์˜€์Šต๋‹ˆ๋‹ค. toastBookmar๋Š” ๋ณด์—ฌ์ฃผ์–ด์•ผ ํ•  Toast์˜ ํ˜•ํƒœ๋ฅผ ๊ฒฐ์ •ํ•˜๋Š” state์ด๊ณ  toast state๋Š” toast๋ฅผ ํ™”๋ฉด์— ๋ Œ๋”๋ง์„ ํŠธ๋ฆฌ๊ฑฐํ•˜๋Š” state๋กœ ์ž‘๋™ํ•˜๋„๋ก ๊ตฌ์„ฑํ•˜์˜€์Šต๋‹ˆ๋‹ค.
  • ์ดํ›„ useEffect๋ฅผ ํ†ตํ•ด setTimeout์„ ์„ค์ •ํ•ด์„œ ์ž‘์—…์„ ํ•˜์˜€์Šต๋‹ˆ๋‹ค. ์˜์กด์„ฑ ๋ฐฐ์—ด์— toastBookmark์™€ toast๋ฅผ ์ถ”๊ฐ€ํ•˜์—ฌ ํ•ด๋‹น ๊ฐ’์ด ๋ณ€๊ฒฝ๋  ๋•Œ ๋งˆ๋‹ค useState๊ฐ€ ์‹คํ–‰๋˜๋„๋ก ์ž‘์„ฑํ•˜์˜€์Šต๋‹ˆ๋‹ค.

10. ๋ฌดํ•œ ์Šคํฌ๋กค ๊ตฌํ˜„

  • "react-intersection-observer"๋ฅผ ํ†ตํ•ด ๊ตฌํ˜„ํ•˜์˜€์Šต๋‹ˆ๋‹ค.
  • ํ™”๋ฉด ๊ฐ„์˜ ์ด๋™์ค‘, ๋ถˆ๋Ÿฌ์˜จ ๋ฌดํ•œ ์Šคํฌ๋กค์ด ์œ ์ง€ ๋˜์ง€ ์•Š๋Š” ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•ด์•ผ ํ•  ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

CODE REFACTORING

1. Router ์ˆ˜์ •ํ•˜๊ธฐ

  • ์ฒ˜์Œ์œผ๋กœ createBrowserRouter๋ฅผ ํ”„๋กœ์ ํŠธ์— ์‹œ๋„ํ•ด ๋ณด์•˜์„ ๋•Œ, ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๊ฒฝ๊ณ ๊ฐ€ ์ฝ˜์†”์— ๋‚˜ํƒ€๋‚ฌ์Šต๋‹ˆ๋‹ค.
history.ts:487 You rendered descendant <Routes> (or called `useRoutes()`) at "/" (under <Route path="/">) but the parent route path has no trailing "*". This means if you navigate deeper, the parent won't match anymore and therefore the child routes will never render.

Please change the parent <Route path="/"> to <Route path="*">.
  • ์ด๋Š” Routes๋ฅผ ์ค‘์ฒฉ์œผ๋กœ ์‚ฌ์šฉํ•˜์—ฌ ์ƒ๊ธด ์œ„ํ—˜ ๊ฒฝ๊ณ  ์˜€์Šต๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ createBrowserRouter, BrowserRouter์ค‘ ํ•˜๋‚˜๋ฅผ ์„ ํƒํ•ด์„œ ์ ์šฉ์„ ํ•ด์•ผ ํ–ˆ์Šต๋‹ˆ๋‹ค.

  • ์ด๋ฅผ ์œ„ํ•œ ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•์œผ๋กœ Outlet์„ ํ™œ์šฉํ•˜๋Š” ๊ฒƒ์ด์—ˆ์Šต๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ์ €์˜ ์ฝ”๋“œ์—์„œ ์ „์—ญ์—์„œ ๊ด€๋ฆฌํ•ด์•ผ ํ•  state๋ฅผ ๋ฟŒ๋ ค ์ฃผ๊ณ  ์žˆ๋Š” ์ƒํ™ฉ์—์„œ Outlet์—์„œ Prop ์ „๋‹ฌ์„ ํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•์ด ์—†์—ˆ์Šต๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ contextAPIํ˜น์€ reducer๋ฅผ ํ™œ์šฉํ•ด์„œ ์ด๋ฅผ ๊ด€๋ฆฌํ•˜๊ณ ์ž ํ•ฉ๋‹ˆ๋‹ค.

  • ๋ฌผ๋ก  useRoutes๋‚˜ loader์™€ ๊ฐ™์€ ์ƒˆ๋กœ์šด ๊ธฐ๋Šฅ์„ ํ™œ์šฉํ•˜๋ฉด ๋˜์ง€๋งŒ, ์ œํ•œ๋œ ์‹œ๊ฐ„ ๋‚ด์— ์ด๋ฅผ ๋‹ค์‹œ ํ•™์Šตํ•˜๋Š” ๊ฒƒ์€ ์–ด๋ ค์›€์ด ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ ์ด๋ฅผ ์ƒˆ๋กœ์šด reducer๋ฅผ ๋งŒ๋“ค์–ด์„œ ๊ด€๋ฆฌํ•˜๊ณ ์ž ํ•ฉ๋‹ˆ๋‹ค. ์ถ”ํ›„ createBrowerRouter๋ฅผ ํ•™์Šตํ•˜๊ณ ์ž ํ•ฉ๋‹ˆ๋‹ค.

2 CSS ์ˆ˜์ •ํ•˜๊ธฐ

  • Theme์˜ ํ˜•ํƒœ๋ฅผ ๋ณ€๊ฒฝํ–ˆ์Šต๋‹ˆ๋‹ค.
  • GlobalStyle์˜ #root์— base font-size๋ฅผ ์ง€์ •ํ•œ ํ›„ ๋ชจ๋“œ ์ƒ๋Œ€ ์ˆ˜์น˜์ธ rem์œผ๋กœ ๋ณ€๊ฒฝํ–ˆ์Šต๋‹ˆ๋‹ค.
  • margin ๊ด€๋ฆฌ๋ฅผ spacing06, spacing11๋กœ ๋ณ€๊ฒฝํ–ˆ์Šต๋‹ˆ๋‹ค. ์ด๋Š” ํ•ด๋‹น ์‚ฌ์ดํŠธ๋ฅผ ์ฐธ๊ณ ํ•˜์—ฌ ๋ณ€๊ฒฝํ–ˆ์Šต๋‹ˆ๋‹ค. ๋งํฌ

3 Util Directory์˜ getRandomForSlice ์ˆ˜์ •ํ•˜๊ธฐ

  • ์ฒ˜์Œ์˜ ์ˆ˜์ • ๋ฐฉํ–ฅ์€ random์œผ๋กœ ๋ฝ‘์€ ์ˆซ์ž๊ฐ€ ๋ฐฐ์—ด ๋ฐ์ดํ„ฐ์˜ ๊ธธ์ด - 4๋ณด๋‹ค ํด์‹œ ์ฃผ์–ด์ง„ ๋ฐฐ์—ด์—์„œ [99,0,1,2]์‹์œผ๋กœ ๋ฝ‘์•„๋‚ผ ๋ฐฉ์‹์œผ๋กœ ์ˆ˜์ •ํ•˜๋ ค ํ–ˆ๋‹ค. ๊ตฌํ˜„ํ•œ ์ฝ”๋“œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.
export default getRandomForSlice(data){
  const random = Math.floor(Math.random() * 100);
  const { length } = data;
  const sliceData = [];
  for (let i = random; i < random + 4; i++) {
    if (i > length - 1) {
      sliceData.push({...data[i - length]});
    } else {
      sliceData.push({...data[i]});
    }
  }
  return sliceData;
}
  • ์ด๋ ‡๊ฒŒ ํ•ด์„œ ์ƒˆ๋กœ์šด ๋ฐฐ์—ด์„ ๋งŒ๋“ค๊ณ  ์ด๋ฅผ state๋กœ ๊ด€๋ฆฌ ํ• ๋•Œ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•˜์˜€๋‹ค. bookmark๊ฐ€ ๋ ์‹œ ๋ณ„ ๋งˆํฌ์˜ ์ƒ‰์ด ๋ณ€ํ™”ํ•ด์•ผ ํ•˜๋Š”๋ฐ, ๊ธฐ์กด์˜ stateํ˜•ํƒœ๋ฅผ ๊ณ ์ •์œผ๋กœ ๊ฐ€์ง€๊ณ  ์žˆ๊ธฐ์— redux์™€ ์—ฐ๋™๋œ ์ƒˆ๋กœ์šด ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ›์•„์˜ค์ง€ ๋ชปํ•˜๊ณ  setState๋ฅผ ์ž์‹ ์ปดํฌ๋„ŒํŠธ์—๊ฒŒ ๋„˜๊ฒจ ์ˆ˜์ •ํ•ด์ฃผ์–ด์•ผ ํ–ˆ๋‹ค. ์ด๋Š” ๋ถˆํ•„์š”ํ•œ ์ž‘์—…์ด๋ผ๊ณ  ๋А๊ปด์„œ ๊ธฐ์กด์˜ ๋ฐฉ์‹์ฒ˜๋Ÿผ number ๋ฐ์ดํ„ฐ๋ฅผ ๋„˜๊ฒจ์ฃผ๋Š” ํ˜•์‹์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์œผ๋กœ ์ฑ„ํƒํ•˜์˜€๋‹ค.
  • ๋งŒ์•ฝ ์ด๋ ‡๊ฒŒ ๋ฝ‘์•„์˜จ ๋ฐฐ์—ด์„ state๋กœ ๊ด€๋ฆฌํ•˜์ง€ ์•Š์„์‹œ ๋ถ๋งˆํฌ ํด๋ฆญ์‹œ ๋ชจ๋“  ์ƒํ’ˆ ๋ฆฌ์ŠคํŠธ๊ฐ€ ์žฌ๋ Œ๋”๋ง ๋˜๊ธฐ ๋•Œ๋ฌธ์—, ์‚ฌ์šฉ ์ธก๋ฉด์—์„œ ๋ถˆํŽธํ•จ์„ ๊ฒฝํ—˜ํ–ˆ๋‹ค.
  • ๊ทธ๋ž˜์„œ ๊ธฐ์กด์˜ RandomNum์„ ๋ฝ‘์•„์ฃผ๋Š” ํ˜•์‹์„ ์‚ฌ์šฉํ•˜์˜€๊ณ  ์ฝ”๋“œ๋ฅผ ์ตœ์ข…์ ์œผ๋กœ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ˆ˜์ •ํ•˜์˜€๋‹ค.
export default function getRandomForSlice(data, chooseNum) {
  return Math.floor(Math.random() * data.length - chooseNum);
}
  • ๋ฟŒ๋ ค์ค„ ๋ฐ์ดํ„ฐ์˜ ๊ฐœ์ˆ˜๊ฐ€ ๋ณ€๊ฒฝ, ํ˜น์€ ์ „์ฒด ๋ฐ์ดํ„ฐ์˜ ๊ฐœ์ˆ˜๊ฐ€ ๋ณ€๊ฒฝ๋  ๊ฒƒ์„ ๊ณ ๋ คํ–ˆ์Šต๋‹ˆ๋‹ค.
  • ๋ Œ๋”๋ง ํ•  ๋ฐ์ดํ„ฐ์˜ ๊ฐœ์ˆ˜๊ฐ€ ๋ณ€ํ™”ํ•  ๊ฒฝ์šฐ Home์—์„œ ์ƒ์ˆ˜๋กœ ๊ด€๋ฆฌํ•˜๊ณ  ์žˆ๋Š” ๋ณ€์ˆ˜๋งŒ ์กฐ์ ˆํ•  ๊ฒฝ์šฐ ์ž๋™์œผ๋กœ ๋ Œ๋”๋ง ๋˜๋„๋ก ์ˆ˜์ •ํ–ˆ์Šต๋‹ˆ๋‹ค.

4. ํ—ค๋” ์ปดํฌ๋„ŒํŠธ์˜ ํ–„๋ฒ„๊ฑฐ ์•„์ด์ฝ˜ ํด๋ฆญ ์ „์—ญ์—์„œ ๊ด€๋ฆฌํ•˜๊ธฐ.

  • ์ด์ „์—๋Š” APP์— state๋ฅผ ์„ค์ •ํ•ด์„œ ๊ฐ ํŽ˜์ด์ง€์— ๋ฟŒ๋ ค์ฃผ๋Š” ํ˜•์‹์œผ๋กœ ์ง„ํ–‰ํ–ˆ์Šต๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ router๋ฅผ ์ˆ˜์ • ํ•˜๋Š” ๊ณผ์ •์—์„œ ๊ฐ ๊ธฐ๋Šฅ์„ ๋ถ„๋ฆฌํ•˜๋Š” ๊ฒŒ ์ข‹์„ ๊ฒƒ ๊ฐ™์•„ ์ด๋ฅผ ์ „์—ญ ๊ด€๋ฆฌ ๋ณ€์ˆ˜๋กœ ๋ณ€๊ฒฝํ–ˆ์Šต๋‹ˆ๋‹ค.
  • hambegerReducer๋ฅผ ๋งŒ๋“ค์–ด ๊ด€๋ฆฌ๋ฅผ ํ•˜์˜€์œผ๋ฉฐ, ๊ฐ ํŽ˜์ด์ง€์—์„œ Dropdown ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์—ด๋ ค ์žˆ์„์‹œ ํ™”๋ฉด ์–ด๋””๋ฅผ ํด๋ฆญํ•ด๋„ ๋‹ซํžˆ๋„๋ก ํ•˜๊ธฐ ์œ„ํ•ด์„œ ๋ณ„๊ฐœ์˜ ํ›… useClick์„ ๋งŒ๋“ค์–ด์„œ ์ฝ”๋“œ๋ฅผ ์ˆ˜์ •ํ–ˆ์Šต๋‹ˆ๋‹ค.

5. Toast UI ์ž‘๋™ ๋ฐฉ์‹ refactioring.

  • ์ตœ์ƒ์œ„ ์ปดํฌ๋„ŒํŠธ์ธ APP์—์„œ ์ „์—ญ์œผ๋กœ toast๊ด€๋ จ state๋ฅผ ์„ค์ •ํ•˜์—ฌ ๊ฐ๊ฐ์˜ ํŽ˜์ด์ง€์˜ ์นด๋“œ ์ปดํฌ๋„ŒํŠธ์— ๋ฟŒ๋ ค์ฃผ๋Š” ๋ฐฉ์‹์œผ๋กœ tost UI๋ฅผ ๋งŒ๋“ค์—ˆ์Šต๋‹ˆ๋‹ค. ์ด๋•Œ ๋งˆ์ฃผ์นœ ๋ฌธ์ œ๋Š” ์ด ๋‘ ๊ฐ€์ง€ ์˜€์Šต๋‹ˆ๋‹ค.
    1. state ๊ด€๋ฆฌ๊ฐ€ ์–ด๋ ค์› ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ ‡๊ฒŒ ๊นŠ์€ ๊ตฌ์กฐ๋„ ์•„๋‹ˆ์ง€๋งŒ, state๊ฐ€ ์ž˜๋ชป ๋˜์—ˆ์„ ์‹œ ์ˆ˜์ • ํ•˜๋Š” ๋ฐฉ๋ฒ•์ด ์‰ฝ์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค.
    2. ํ•˜๋‚˜์˜ toast ui๋ฅผ ๊ด€๋ฆฌํ•˜๋Š” ๊ฒƒ์€ ์ถฉ๋ถ„ํ–ˆ์ง€๋งŒ, ๋ฐฐ์—ด ํ˜•์‹์œผ๋กœ state๋ฅผ ๊ด€๋ฆฌํ•˜๊ณ ์ž ํ• ๋•Œ ํ•˜๋“œ ์ฝ”๋”ฉ์ด ๋˜๊ณ  ํ•˜๋‚˜์˜ state์— ๋„ˆ๋ฌด ๋งŽ์€ ๊ฐ’์„ ๊ด€๋ฆฌํ•˜๊ฒŒ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.
Vite.+.React.1.mp4
  • useReducer๋ฅผ ํ™œ์šฉํ•˜๋ฉด ๋ฐ์ดํ„ฐ๊ฐ€ ๋ณต์žกํ•ด์ง€๋Š” ๊ตฌ์กฐ๋Š” ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ์ง€๋งŒ, ์—ฌ์ „ํžˆ state ๊ด€๋ฆฌ๊ฐ€ ์–ด๋ ต๋‹ค๋Š” ๋ฌธ์ œ๊ฐ€ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ contextAPI์™€ ํ•จ๊ป˜ ์‚ฌ์šฉ์„ ํ•ด์•ผ ํ–ˆ์Šต๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ํ˜„์žฌ ์ „์—ญ ์ƒํƒœ๊ด€๋ฆฌ๋กœ redux๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ๊ธฐ ๋•Œ๋ฌธ์— redux๋ฅผ ํ™œ์šฉํ•˜๊ธฐ๋กœ ํ•˜์˜€์Šต๋‹ˆ๋‹ค.
  • ๋น„๋™๊ธฐ๋กœ ๋™์ž‘ํ•˜์—ฌ ๋ฐ์ดํ„ฐ๋ฅผ ์ฒ˜๋ฆฌํ•ด์•ผ ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๊ด€๋ จ middleware์ธ redux-thunk๋ฅผ ์„ค์น˜ํ•˜์—ฌ ์ƒˆ๋กœ์šด reducer๋ฅผ ๋งŒ๋“ค์—ˆ์Šต๋‹ˆ๋‹ค. (toastReducer)
  • toastReducer๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ๋น„์›Œ๋‘” ์ƒํƒœ๋กœ ๊ด€๋ฆฌํ•˜๋Š” ๊ฒƒ์„ ๋ชฉํ‘œ๋กœ ํ–ˆ์Šต๋‹ˆ๋‹ค. ๋นˆ ๋ฐฐ์—ด์„ ์ดˆ๊ธฐ ๋ฐ์ดํ„ฐ๋กœ ์„ค์ •ํ•˜์—ฌ ์ƒˆ๋กœ์šด ๋ฐ์ดํ„ฐ๊ฐ€ ๋“ค์–ด์˜ค๋ฉด ํ•˜๋‚˜์”ฉ ์Œ“์ด๊ณ  ์ฒ˜์Œ ๋“ค์–ด์˜จ ๋ฐ์ดํ„ฐ ๋ถ€ํ„ฐ ์ œ๊ฑฐ๋˜๋Š” queue๋ฅผ ์ฐจ์šฉํ•ด์„œ reducer์˜ ๊ตฌ์กฐ๋ฅผ ์ž‘์„ฑํ–ˆ์Šต๋‹ˆ๋‹ค.
Vite.+.React.4.mp4

6. MODAL ๋ฒ„๊ทธ ํ”ฝ์Šค

  • ๊ธฐ์กด์—๋Š” Modal์„ Card ์ปดํฌ๋„ŒํŠธ ์•ˆ์— ์œ„์น˜ํ•˜๊ฒŒ ํ•˜์˜€์Šต๋‹ˆ๋‹ค. ์ด๋•Œ ์ •์ƒ์ ์œผ๋กœ ์ž‘๋™ํ•˜์ง€๋งŒ, ๋ถ๋งˆํฌ ํŽ˜์ด์ง€์—์„œ ๋ถ๋งˆํฌ๋ฅผ ํ•ด์ œํ• ์‹œ Card component๊ฐ€ unmount๋˜๋ฉด์„œ Modal ๋˜ํ•œ ๊ฐ•์ œ๋กœ ์ข…๋ฃŒ๋˜๋Š” ํ˜„์ƒ์ด ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค. (์œ„์˜ ์˜์ƒ์—์„œ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.)
  • ๋”ฐ๋ผ์„œ Modal ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ „์—ญ์—์„œ ์„ค์ •ํ•ด์„œ redux๋ฅผ ํ†ตํ•ด ์ƒํƒœ ๊ด€๋ฆฌ๋ฅผ ํ•˜๋„๋ก ์ˆ˜์ •ํ•˜์˜€์Šต๋‹ˆ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด ๋ฒ„๊ทธ๋ฅผ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.
Vite.+.React.5.mp4

7. ์ปดํฌ๋„ŒํŠธ ์ˆ˜์ •

1. Card ์ปดํฌ๋„ŒํŠธ ์ˆ˜์ •

// ./pages/home.js
            <section>
              <Title>์ƒํ’ˆ ๋ฆฌ์ŠคํŠธ</Title>
              <List>
                {state
                  .slice(randomNumber, randomNumber + CHOOSENUMBER)
                  .map((item) => (
                    <li key={item.id}>
                      <Card data={item} />
                    </li>
                  ))}
              </List>
            </section>
  • ์œ„์˜ ์ฝ”๋“œ๋ฅผ ๋‹ค์Œ๊ณผ ๊ฐ™์ด Component๋กœ ๋ถ„๋ฆฌํ•˜์—ฌ ์ˆ˜์ •ํ•˜์˜€์Šต๋‹ˆ๋‹ค.
            <CardList
              title={"์ƒํ’ˆ ๋ฆฌ์ŠคํŠธ"}
              state={state.slice(randomNumber, randomNumber + CHOOSENUMBER)}
            />

2. ๋ฌธ์ž์—ด์„ ๊ฐ์ฒด๋กœ ๊ด€๋ฆฌ

  • ์ด์ „์—๋Š” ์ง์ ‘ ํ•˜๋“œ ํƒ€์ดํ•‘ ํ•˜๋Š” ์‹์œผ๋กœ ๋ฌธ์ž์—ด์„ ์‚ฌ์šฉํ–ˆ์Šต๋‹ˆ๋‹ค.
  • ๋ฐ˜๋ณต์ ์œผ๋กœ ์‚ฌ์šฉ๋˜๋Š” ๋ฌธ์ž์—ด์„ ๊ฐ์ฒด๋กœ ๊ด€๋ฆฌํ•˜์—ฌ ์‹ค์ˆ˜๊ฐ€ ๋‚˜์˜ค๋Š” ๋ถ€๋ถ„์„ ์ค„์˜€์Šต๋‹ˆ๋‹ค.
// ./src/components/Description.jsx
const cardType = {
  product: "Product",
  category: "Category",
  brand: "Brand",
  exhibition: "Exhibition",
};

3. ๋ถ๋งˆํฌํŽ˜์ด์ง€, ์ƒํ’ˆ๋ฆฌ์ŠคํŠธ ํŽ˜์ด์ง€ ํ†ตํ•ฉ๊ด€๋ฆฌ

  • ๊ธฐ์กด์—๋Š” ๋ฟŒ๋ ค์ฃผ๋Š” ๋ฐ์ดํ„ฐ๋งŒ ๋‹ค๋ฅด๊ณ  ๋™์ผํ•œ ํŽ˜์ด์ง€๋ฅผ ํ•˜๋“œ์ฝ”๋”ฉํ•ด์„œ ๋ถ„๋ฆฌํ•˜์—ฌ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.
  • ๋”ฐ๋ผ์„œ ์ปดํฌ๋„ŒํŠธ์™€ ํŽ˜์ด์ง€์˜ ์—ญํ• ์„ ๋ถ„๋ฆฌํ–ˆ์Šต๋‹ˆ๋‹ค. ๋‘ ํŽ˜์ด์ง€์˜ ๊ณตํ†ต๋œ ๋ถ€๋ถ„์„ ์ปดํฌ๋„ŒํŠธ๋กœ ๋ฝ‘์•„๋ƒˆ์Šต๋‹ˆ๋‹ค. ๊ฐ๊ฐ์˜ ํŽ˜์ด์ง€๋Š” ์ปดํฌ๋„ŒํŠธ์— ํ•„์š”ํ•œ ๋ฐ์ดํ„ฐ๋ฅผ ์ •์ œํ•˜์—ฌ ๋ฟŒ๋ ค์ฃผ๋Š” ์—ญํ• ์„ ํ•˜๋„๋ก ์ˆ˜์ •ํ–ˆ์Šต๋‹ˆ๋‹ค.

4. ์ˆซ์ž ํƒ€์ž…์„ ํ†ตํ•œ ํŽ˜์ด์ง€ ๊ด€๋ฆฌ์˜ ๋ถˆ๋ช…ํ™•์„ฑ

  • ์ˆซ์ž ํƒ€์ž…์œผ๋กœ ํ•„ํ„ฐ ์ปดํฌ๋„ŒํŠธ๋ฅผ ๊ด€๋ฆฌํ•˜์—ฌ ๋ฟŒ๋ ค์ค„ ๋ฐ์ดํ„ฐ๋ฅผ ์ •ํ–ˆ์Šต๋‹ˆ๋‹ค.
const [numState, setNumState] = useState(0);
 {numState === 0 &&
            state
              .filter((item) => item.bookmarked)
              .map((item) => (
                <li key={item.id}>
                  <Card data={item} />
                </li>
              ))}
  • ์ด๋•Œ์˜ ๋ฌธ์ œ์ ์€ ์–ด๋–ค ๋ฐ์ดํ„ฐ๋ฅผ ์ ์šฉํ•˜๋Š”์ง€๊ฐ€ ๋ช…ํ™•ํ•˜์ง€ ์•Š์•˜์œผ๋ฉฐ, ๋ฐ์ดํ„ฐ๋ฅผ ๋ถ„๋ฅ˜ํ•˜๋Š” ๋ฐฉ๋ฒ•๋„ ๋ช…ํ™•ํžˆ ์•Œ๊ธฐ ํž˜๋“ค๋‹ค๋Š” ์ ์„ ์•Œ ์ˆ˜ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ ์ˆซ์ž๊ฐ€ ์•„๋‹Œ ์ƒํ’ˆ ํƒ€์ž…์„ ๋ฌธ์ž์—ด๋กœ ์ž‘์„ฑํ•˜์—ฌ ๊ด€๋ฆฌํ•˜๋„๋ก ํ•˜์˜€์Šต๋‹ˆ๋‹ค.
const filterSet = {
  all: "์ „์ฒด",
  product: "์ƒํ’ˆ",
  categoryl: "์นดํ…Œ๊ณ ๋ฆฌ",
  exhibition: "๊ธฐํš์ „",
  brand: "๋ธŒ๋žœ๋“œ",
};

 {filterState === filterSet.all && (
        <CardList state={state.slice(0, dataNum)} />
      )}
  • ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๋ฟŒ๋ ค์ค„ ๋ฐ์ดํ„ฐ๋ฅผ ๊ด€๋ฆฌํ•˜๋Š” ํ•„ํ„ฐ๋ฅผ ๋ฌธ์ž์—ด๋กœ ํ•˜์—ฌ ๋ช…ํ™•ํžˆ ์ฝ”๋“œ๋ฅผ ๋ณด๊ณ  ์˜๋„๋ฅผ ํŒŒ์•…ํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•˜์˜€์Šต๋‹ˆ๋‹ค.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages