Giter Site home page Giter Site logo

sypear / daengnyang-market-client Goto Github PK

View Code? Open in Web Editor NEW

This project forked from daengnyang-market/daengnyang-market-client

0.0 0.0 0.0 7.37 MB

๐Ÿถ ๊ฐ€์ ธ๋„๋Œ•๋ƒฅ : ์šฐ๋ฆฌ์ง‘ ๋Œ•๋ƒฅ์ด๋ฅผ ์œ„ํ•œ ๋”ฐ๋œปํ•œ ์„ ๋ฌผ ๐Ÿฑ

JavaScript 99.02% CSS 0.80% HTML 0.18%
javascript react styled-components

daengnyang-market-client's Introduction

๐Ÿพ ๊ฐ€์ ธ๋„๋Œ•๋ƒฅ

๐Ÿ“Ž ๋ฐฐํฌ URL


์ด๋ฉ”์ผ ๋กœ๊ทธ์ธ ํ…Œ์ŠคํŠธ ๊ณ„์ •



1. ์„œ๋น„์Šค ์†Œ๊ฐœ

๊ฐ€์ ธ๋„๋Œ•๋ƒฅ์€ ๋ฐ˜๋ ค๋™๋ฌผ์„ ์‚ฌ๋ž‘ํ•˜๋Š” ํŒปํŽจ์กฑ์„ ์œ„ํ•œ SNS/์ปค๋ฎค๋‹ˆํ‹ฐ ์„œ๋น„์Šค์ž…๋‹ˆ๋‹ค.

  • ๋ฐ˜๋ ค๋™๋ฌผ์ด ์“ฐ๋˜ ๋ฌผ๊ฑด์„ ์ค‘๊ณ ๋กœ ํŒ๋งค/๊ตฌ๋งคํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ์ƒํ’ˆ์„ ํŒ๋งค/๊ตฌ๋งคํ•˜์ง€ ์•Š์•„๋„ ์ผ์ƒ์„ ๊ณต์œ ํ•˜๋ฉฐ ์ฆ๊ฑฐ์šด SNS ํ™œ๋™์„ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ๋ฐ˜๋ ค๋™๋ฌผ ์ปค๋ฎค๋‹ˆํ‹ฐ ์„œ๋น„์Šค๋ฅผ ์ด์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

(Top)


2. ํŒ€์› ์†Œ๊ฐœ

FE ๊น€๋ฏผ์Šน FE ๊น€์˜ํ˜ธ FE ๋ฐฐ์Šน์—ฐ FE ์ด๊ด‘๋ ฌ
๐Ÿ”— GitHub
๋””์ž์ธ ๋ฆฌ๋”
๐Ÿ”— GitHub
๊ธฐํš ๋ฆฌ๋”
๐Ÿ”— GitHub
ํ”„๋กœ์ ํŠธ ๋งค๋‹ˆ์ €
๐Ÿ”— GitHub
๊ฐœ๋ฐœ ๋ฆฌ๋”

(Top)


3. ๊ฐœ๋ฐœ ํ™˜๊ฒฝ ๋ฐ ๊ธฐ์ˆ  ์Šคํƒ

3-1. ๊ฐœ๋ฐœ ํ™˜๊ฒฝ

  • IDE : Visual Studio Code 1.74.2
  • OS : macOS Monterey, Windows 10

3-2. ๊ธฐ์ˆ  ์Šคํƒ

  • FE : React v18, Styled-components v5, Axios v1.2.1
  • BE : ์ œ๊ณต๋œ API ์‚ฌ์šฉ

3-3. ํ˜‘์—… ํˆด

  • ๋ฒ„์ „ ๊ด€๋ฆฌ : Git, GitHub
  • ์ง„ํ–‰ ์ƒํ™ฉ ๊ด€๋ฆฌ(์นธ๋ฐ˜ ๋ณด๋“œ) : GitHub Projects
  • ์ด์Šˆ ๊ด€๋ฆฌ : GitHub Issues
  • ๋ฌธ์„œ ๊ด€๋ฆฌ : Notion
  • ๋ฉ”์‹ ์ € : Discord

3-4. ํ…Œ์ŠคํŠธ ํˆด

  • API ํ…Œ์ŠคํŠธ : Postman

(Top)


4. ํ”„๋กœ์ ํŠธ ๊ตฌ์กฐ

  • public/favicon/ : ํŒŒ๋น„์ฝ˜
  • src/assets/ : ์„œ๋น„์Šค์—์„œ ์‚ฌ์šฉํ•˜๋Š” ์—์…‹ ํŒŒ์ผ (ํฐํŠธ, ์•„์ด์ฝ˜, ์ด๋ฏธ์ง€)
  • src/components/ : ์„œ๋น„์Šค์—์„œ ์‚ฌ์šฉํ•˜๋Š” ์ปดํฌ๋„ŒํŠธ (์บ๋Ÿฌ์…€, ๊ณตํ†ต ์ปดํฌ๋„ŒํŠธ, ๊ณตํ†ต ๋ ˆ์ด์•„์›ƒ)
  • src/context/ : ์ „์—ญ ๋ฐ์ดํ„ฐ๋ฅผ ๊ณต์œ ํ•˜๊ธฐ ์œ„ํ•ด ์ •์˜ํ•œ Context ํŒŒ์ผ
  • src/hooks/ : ์žฌ์‚ฌ์šฉ์„ ์œ„ํ•ด ๋ถ„๋ฆฌํ•œ Custom Hook
  • src/pages/ : ๊ณตํ†ต ์ปดํฌ๋„ŒํŠธ๋ฅผ ์‚ฌ์šฉํ•ด ๋งŒ๋“  ํŽ˜์ด์ง€
  • src/routes/ : ํŽ˜์ด์ง€ ๋ผ์šฐํŒ…์„ ์œ„ํ•œ ํŒŒ์ผ
  • src/styles/ : ์ „์—ญ ์Šคํƒ€์ผ ํŒŒ์ผ
  • src/utils/ : ์žฌ์‚ฌ์šฉ์„ ์œ„ํ•ด ๋ถ„๋ฆฌํ•œ ์œ ํ‹ธ ํŒŒ์ผ
๐Ÿ“ฆ ๊ฐ€์ ธ๋„๋Œ•๋ƒฅ
โ”œโ”€ ๐Ÿ“ฆ public
โ”‚ย ย โ”œโ”€ย ๐Ÿ“‚ favicon
โ”‚ย ย โ””โ”€ย ๐Ÿ“œ index.html
โ””โ”€ย ๐Ÿ“ฆ src
ย ย ย โ”œโ”€ย ๐Ÿ“‚ assets
ย ย ย โ”‚ย ย โ”œโ”€ย ๐Ÿ“‚ fonts
ย ย ย โ”‚ย ย โ”œโ”€ย ๐Ÿ“‚ icons
ย ย ย โ”‚ย ย โ””โ”€ย ๐Ÿ“‚ images
ย ย ย โ”œโ”€ย ๐Ÿ“‚ components
ย ย ย โ”‚ย ย โ”œโ”€ย ๐Ÿ“‚ carousel
ย ย ย โ”‚ย ย โ”œโ”€ย ๐Ÿ“‚ common
ย ย ย โ”‚ย ย โ””โ”€ย ๐Ÿ“‚ layout
ย ย ย โ”œโ”€ย ๐Ÿ“‚ context
ย ย ย โ”œโ”€ย ๐Ÿ“‚ hooks
ย ย ย โ”œโ”€ย ๐Ÿ“‚ pages
ย ย ย โ”‚ย ย โ”œโ”€ย ๐Ÿ“‚ ChatPage
ย ย ย โ”‚ย ย โ”œโ”€ย ๐Ÿ“‚ CommunityPage
ย ย ย โ”‚ย ย โ”œโ”€ย ๐Ÿ“‚ FeedPage
ย ย ย โ”‚ย ย โ”œโ”€ย ๐Ÿ“‚ FollowListPage
ย ย ย โ”‚ย ย โ”œโ”€ย ๐Ÿ“‚ JoinPage
ย ย ย โ”‚ย ย โ”œโ”€ย ๐Ÿ“‚ LoginPage
ย ย ย โ”‚ย ย โ”œโ”€ย ๐Ÿ“‚ NotFoundPage
ย ย ย โ”‚ย ย โ”œโ”€ย ๐Ÿ“‚ PostPage
ย ย ย โ”‚ย ย โ”œโ”€ย ๐Ÿ“‚ ProductPage
ย ย ย โ”‚ย ย โ”œโ”€ย ๐Ÿ“‚ ProfileModificationPage
ย ย ย โ”‚ย ย โ”œโ”€ย ๐Ÿ“‚ ProfilePage
ย ย ย โ”‚ย ย โ”œโ”€ย ๐Ÿ“‚ SearchPage
ย ย ย โ”‚ย ย โ””โ”€ ๐Ÿ“‚ย SplashScreen
ย ย ย โ”œโ”€ย ๐Ÿ“‚ routes
ย ย ย โ”œโ”€ย ๐Ÿ“‚ styles
ย ย ย โ”œโ”€ย ๐Ÿ“‚ utils
   โ”œโ”€ย ๐Ÿ“œ App.jsx
   โ””โ”€ย ๐Ÿ“œ index.jsx

(Top)


5. Git Branch ์ „๋žต

แ„‰แ…ณแ„แ…ณแ„…แ…ตแ†ซแ„‰แ…ฃแ†บ 2023-01-04 แ„‹แ…ฉแ„’แ…ฎ 3 50 02

  • ์†Œ๊ทœ๋ชจ ํ”„๋กœ์ ํŠธ์— ๋งž๊ฒŒ Main, Develop, Feature ์„ธ Branch๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์ „๋žต ์‚ฌ์šฉ

(Top)


6. ๊ฐœ๋ฐœ ์ผ์ •

๐Ÿ”ฅ 2022-12-09 ~ 2023-01-05

แ„‘แ…ญ

  • ์š”๊ตฌ์‚ฌํ•ญ ํŒŒ์•… ๋ฐ ํ”„๋กœ์ ํŠธ ๊ทœ์น™ ์„ค๋ฆฝ : 2022-11-29 ~ 2022-12-09
  • ๊ณตํ†ตUI ์ปดํฌ๋„ŒํŠธ ๊ฐœ๋ฐœ : 2022-12-09 ~ 2022-12-13
  • ํŽ˜์ด์ง€ ํผ๋ธ”๋ฆฌ์‹ฑ : 2022-12-13 ~ 2022-12-17
  • ๊ธฐ๋Šฅ ๊ฐœ๋ฐœ : 2022-12-16 ~ 2022-12-27
  • ๋ฒ„๊ทธ ์ˆ˜์ • ๋ฐ ์œ ์ง€๋ณด์ˆ˜ : 2022-12-26 ~ 2023-01-05

(Top)


7. ํ˜‘์—… ๋ฌธํ™”

๐Ÿ’ช ํŒ€์›Œํฌ ๊ฐ•ํ™”

- ์„ค๋ฌธ์ง€ ์ž‘์„ฑ

  • ํ”„๋กœ์ ํŠธ ์‹œ์ž‘ ์ „, ๊ณตํ†ต๋œ ํŒ€ ๋ชฉํ‘œ๋ฅผ ์„ธ์šฐ๊ณ  ์‹œ๋„ˆ์ง€๋ฅผ ๊ฐ•ํ™”ํ•˜๊ธฐ ์œ„ํ•ด ๋„ค์ด๋ฒ„ํผ ์„ค๋ฌธ ์ง„ํ–‰

- ๋ชจ๋‘๊ฐ€ ์ฐธ์—ฌํ•˜๋Š” ํšŒ์˜

แ„‰แ…ณแ„แ…ณแ„…แ…ตแ†ซแ„‰แ…ฃแ†บ 2023-01-05 แ„‹แ…ฉแ„Œแ…ฅแ†ซ 11 15 49

  • ๊ณต๋™ ์ž‘์—…ํˆด์ธ Figzam์„ ์ด์šฉํ•œ ํšŒ์˜
  • ๋”ฑ๋”ฑํ•œ ๋ถ„์œ„๊ธฐ์˜ ํšŒ์˜๊ฐ€ ์•„๋‹ˆ๋ผ ๋ชจ๋‘๊ฐ€ ์ฐธ์—ฌํ•  ์ˆ˜ ์žˆ๋Š” ๊ฐ€๋ฒผ์šด ๋ถ„์œ„๊ธฐ์—์„œ ํšŒ์˜๋ฅผ ์ง„ํ–‰

๐Ÿ“Œ ์—…๋ฌด ๊ณต์œ 

- ๋ฐ์ผ๋ฆฌ ์Šคํฌ๋Ÿผ

  • ๋งค์ผ 9์‹œ 20๋ถ„ ๋ฐ์ผ๋ฆฌ ์Šคํฌ๋Ÿผ์„ ํ†ตํ•ด ์—…๋ฌด ๊ณต์œ  ๋ฐ ์ง„ํ–‰ ์ƒํ™ฉ ํŒŒ์•…

โœ ๊ฐœ๋ฐœ ๊ทœ์น™ ๊ด€๋ฆฌ

- GitHub Wiki์— ๊ฐœ๋ฐœ ๊ทœ์น™ ๋“ฑ๋ก


๐ŸŽฏ ๋ชฉํ‘œ ๊ด€๋ฆฌ

- GitHub Milestones์„ ์ด์šฉํ•œ ๋‹จ๊ณ„๋ณ„ ๋ชฉํ‘œ ๊ด€๋ฆฌ

แ„‰แ…ณแ„แ…ณแ„…แ…ตแ†ซแ„‰แ…ฃแ†บ 2023-01-04 แ„‹แ…ฉแ„’แ…ฎ 3 37 23

  • ํ”„๋กœ์ ํŠธ ๋‹จ๊ณ„๋ณ„ ๋ชฉํ‘œ๋ฅผ ๋ช…ํ™•ํ•˜๊ฒŒ ํ•˜๊ธฐ ์œ„ํ•ด ๋งˆ์ผ์Šคํ†ค ๋“ฑ๋ก
  • GitHub ์ด์Šˆ ๋“ฑ๋ก ์‹œ ๊ด€๋ จ๋œ ๋งˆ์ผ์Šคํ†ค ์„ ํƒ

๐Ÿช„ ์ด์Šˆ ๊ด€๋ฆฌ ํ”„๋กœ์„ธ์Šค

- ์ž‘์—… ์ „ GitHub Issues ๋“ฑ๋ก

  • ์•„๋ฌด๋ฆฌ ์ž‘์€ ์ž‘์—…์ด๋ผ๋„ ์ˆ˜์›”ํ•œ ์ด์Šˆ ์ถ”์ ์„ ์œ„ํ•ด ์ด์Šˆ ๋ฐ˜๋“œ์‹œ ๋“ฑ๋ก ํ›„ ์ž‘์—… ์ง„ํ–‰ (์ž‘์—… ํ•˜๋‚˜๋‹น ์ด์Šˆ ํ•˜๋‚˜) แ„‰แ…ณแ„แ…ณแ„…แ…ตแ†ซแ„‰แ…ฃแ†บ 2023-01-05 แ„‹แ…ฉแ„Œแ…ฅแ†ซ 10 50 20
  • ์ปจ๋ฒค์…˜ ํ†ต์ผ์„ ์œ„ํ•ด ์ด์Šˆ ํ…œํ”Œ๋ฆฟ ์‚ฌ์šฉ

- ์ด์Šˆ ํ•ด๊ฒฐ ํ›„ Pull Request ์ƒ์„ฑ

  • ์ปจ๋ฒค์…˜ ํ†ต์ผ์„ ์œ„ํ•ด PR ํ…œํ”Œ๋ฆฟ ์‚ฌ์šฉ
  • ํŒ€์› 2๋ช… ์ด์ƒ์˜ ์Šน์ธ์„ ๋ฐ›์•„์•ผ ๋จธ์ง€ ๊ฐ€๋Šฅ

๐Ÿ•ต ์ด์Šˆ ์ง„ํ–‰ ์ƒํ™ฉ ๊ด€๋ฆฌ

- GitHub Projects๋ฅผ ์ด์šฉํ•œ ์นธ๋ฐ˜ ๋ณด๋“œ

แ„‰แ…ณแ„แ…ณแ„…แ…ตแ†ซแ„‰แ…ฃแ†บ 2023-01-05 แ„‹แ…ฉแ„Œแ…ฅแ†ซ 10 41 48

  • ์ด์Šˆ ์ง„ํ–‰ ์ƒํ™ฉ์„ ํ•œ ๋ˆˆ์— ๋ณผ ์ˆ˜ ์žˆ๋„๋ก ์นธ๋ฐ˜ ๋ณด๋“œ ํ˜•ํƒœ๋กœ ์‹œ๊ฐํ™”

๐Ÿ“† ์ž‘์—… ์ง„ํ–‰ ์ƒํ™ฉ ๊ด€๋ฆฌ

- ๋…ธ์…˜ ๊ธฐ๋Šฅ๋ณ„ ์ž‘์—… ์ƒํ™ฉ ๊ด€๋ฆฌ ํŽ˜์ด์ง€๋ฅผ ์ž‘์„ฑํ•ด ์ž‘์—… ์ง„ํ–‰ ์ƒํ™ฉ ๊ด€๋ฆฌ

แ„‰แ…ณแ„แ…ณแ„…แ…ตแ†ซแ„‰แ…ฃแ†บ 2023-01-05 แ„‹แ…ฉแ„Œแ…ฅแ†ซ 11 56 42

  • ์ „์ฒด์ ์ธ ์ž‘์—… ์ง„ํ–‰ ์ƒํ™ฉ์„ ํ•œ ๋ˆˆ์— ๋ณผ ์ˆ˜ ์žˆ๋„๋ก ๊ธฐ๋Šฅ๋ณ„ ์ง„ํ–‰ ์ƒํ™ฉ ํ‘œ ์ œ์ž‘
  • ์ง„ํ–‰ ์ „, ์ง„ํ–‰ ์ค‘, ์ง„ํ–‰ ์™„๋ฃŒ, ์ˆ˜์ • ์ค‘ ํƒœ๊ทธ๋ฅผ ์ด์šฉํ•ด ์ง„ํ–‰ ์ƒํ™ฉ ์ฒดํฌ

๐Ÿ› ๋ฒ„๊ทธ ๊ด€๋ฆฌ

- ๋…ธ์…˜ ๋ฒ„๊ทธ ๋ฆฌํฌํŠธ ํŽ˜์ด์ง€๋ฅผ ์ž‘์„ฑํ•ด ๋ฐœ๊ฒฌ๋œ ๋ฒ„๊ทธ ๊ด€๋ฆฌ

แ„‰แ…ณแ„แ…ณแ„…แ…ตแ†ซแ„‰แ…ฃแ†บ 2023-01-05 แ„‹แ…ฉแ„Œแ…ฅแ†ซ 11 59 42

- ๋ฒ„๊ทธ ๊ด€๋ฆฌ ํ”„๋กœ์„ธ์Šค

  1. ๋ฒ„๊ทธ ๋ฐœ๊ฒฌ์ž๊ฐ€ ๋ฒ„๊ทธ ์œ ํ˜•, ๋ฒ„๊ทธ, ๋ฒ„๊ทธ ์ž‘์„ฑ์ž, ๊ฐœ๋ฐœ ๋‹ด๋‹น์ž ๋“ฑ๋ก
    • ๋ฒ„๊ทธ ์ž‘์„ฑ์ž๊ฐ€ ๊ฐœ๋ฐœ ๋‹ด๋‹น์ž์ธ ๊ฒฝ์šฐ : ๋ณธ์ธ ๋“ฑ๋ก
    • ๋ฒ„๊ทธ ์ž‘์„ฑ์ž๊ฐ€ ๊ฐœ๋ฐœ ๋‹ด๋‹น์ž๊ฐ€ ์•„๋‹Œ ๊ฒฝ์šฐ : ํ˜‘์—… ๋ฉ”์‹ ์ €๋กœ ๋‚ด์šฉ ๊ณต์œ  ํ›„ ๊ฐœ๋ฐœ ๋‹ด๋‹น์ž ์„ค์ •
  2. ๊ฐœ๋ฐœ ๋‹ด๋‹น์ž๋Š” ๋ฒ„๊ทธ ํ™•์ธ ํ›„ ํ™•์ธ ๊ฒฐ๊ณผ ๋“ฑ๋ก
    • ๊ฑฐ์ ˆ : ๋ฒ„๊ทธ๊ฐ€ ์•„๋‹Œ ๊ฒฝ์šฐ
    • ์Šน์ธ : ๋ฒ„๊ทธ
  3. ์Šน์ธ๋œ ๋ฒ„๊ทธ๋Š” ๊ฐœ๋ฐœ ๋‹ด๋‹น์ž๊ฐ€ ์ด์Šˆ ๋“ฑ๋ก ํ›„ ๋ฒ„๊ทธ ์ˆ˜์ • ์ง„ํ–‰

(Top)


8. ๊ตฌํ˜„ ๊ธฐ๋Šฅ ๋ฐ ๋‹ด๋‹น์ž


(Top)


9. ๊ตฌ์ฒด์ ์ธ ๋‹ด๋‹น ์—…๋ฌด

๐Ÿค ๊ณตํ†ต

์ปจ๋ฒค์…˜ ์„ค๋ฆฝ

  • ์ปค๋ฐ‹ ๋ฉ”์‹œ์ง€ ์ปจ๋ฒค์…˜, ์ฝ”๋“œ ์ปจ๋ฒค์…˜, ๋„ค์ด๋ฐ ์ปจ๋ฒค์…˜, ๋””๋ ‰ํ† ๋ฆฌ ๊ตฌ์กฐ ์ปจ๋ฒค์…˜ ์„ค๋ฆฝ
  • GitHub Wiki์— ์ปจ๋ฒค์…˜ ๊ธฐ๋ก

ํ”„๋กœ์ ํŠธ ๊ด€๋ฆฌ

  • ์ด์Šˆ ๊ด€๋ฆฌ
  • ์ด์Šˆ ์ง„ํ–‰ ์ƒํ™ฉ ๊ด€๋ฆฌ
  • ์ž‘์—… ์ง„ํ–‰ ์ƒํ™ฉ ๊ด€๋ฆฌ
  • ๋ฒ„๊ทธ ๊ด€๋ฆฌ

๋ฌธ์„œ ์ž‘์„ฑ

  • README ์ž‘์„ฑ

๐Ÿฐ ๊น€๋ฏผ์Šน

๐Ÿท๏ธย ํšŒ์˜๋ก ์ž‘์„ฑ


๐ŸŽจย ํ™”๋ฉด ๊ฐœ๋ฐœ

  • ํƒ‘ ๋‚ด๋น„๊ฒŒ์ด์…˜ 5์ข…, ํƒญ ๋ฉ”๋‰ด, ๋Œ“๊ธ€ ์ปดํฌ๋„ŒํŠธ ์ œ์ž‘
  • Splash, ํ”ผ๋“œ, ํ”„๋กœํ•„, 404 ํŽ˜์ด์ง€ ํผ๋ธ”๋ฆฌ์‹ฑ

๐Ÿ”งย ๊ธฐ๋Šฅ ๊ฐœ๋ฐœ

  • ํ™ˆ ํ”ผ๋“œ ํŽ˜์ด์ง€ ๊ธฐ๋Šฅ ๊ตฌํ˜„
    • ํ”ผ๋“œ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ›์•„ ํ™”๋ฉด์— ๊ทธ๋ ค์ฃผ๋Š” ๊ธฐ๋Šฅ ๊ตฌํ˜„ (API ๋ช…์„ธ์— ๋”ฐ๋ฆ„)
    • ๋กœ๊ทธ์ธ ์—ฌ๋ถ€์— ๋”ฐ๋ฅธ ํŽ˜์ด์ง€ ๋กœ๋“œ ๊ธฐ๋Šฅ ๊ตฌํ˜„
      • ๋กœ๊ทธ์•„์›ƒ ์ƒํƒœ์ผ๋•Œ๋Š” ๋กœ๊ทธ์ธ ํŽ˜์ด์ง€ / ๋กœ๊ทธ์ธ ์ƒํƒœ์ผ๋•Œ๋Š” ํŒ”๋กœ์ž‰ ํ”ผ๋“œ ๋ฐ์ดํ„ฐ ๋ฐ›์•„์˜ค๋„๋ก
    • ํ”ผ๋“œ ๋ฐ์ดํ„ฐ ์ œํ•œ ์—†์ด ๋ฐ›์•„์˜ฌ ์ˆ˜ ์žˆ๋„๋ก ํŽ˜์ด์ง€ ๋ฌดํ•œ์Šคํฌ๋กค ๊ตฌํ˜„
  • ํ”„๋กœํ•„ ํŽ˜์ด์ง€ ๊ธฐ๋Šฅ ๊ตฌํ˜„ (์‚ฌ์šฉ์ž ์ •๋ณด, ๋“ฑ๋ก๋œ ์ƒํ’ˆ, ์ž‘์„ฑ๊ธ€ ์กฐํšŒ ๊ธฐ๋Šฅ)
    • ์œ ์ € ์ •๋ณด ๋ฐ ์ƒํ’ˆ, ํฌ์ŠคํŠธ ๋ชฉ๋ก ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ›์•„ ํ™”๋ฉด์— ๊ทธ๋ ค์ฃผ๋Š” ๊ธฐ๋Šฅ ๊ตฌํ˜„ (API ๋ช…์„ธ์— ๋”ฐ๋ฆ„)
    • ํฌ์ŠคํŠธ ๋ชฉ๋ก ๋ ˆ์ด์•„์›ƒ ๋ฆฌ์ŠคํŠธ ํ˜•์‹ / ์•จ๋ฒ” ํ˜•์‹์œผ๋กœ ์„ ํƒํ•ด์„œ ๋ณผ ์ˆ˜ ์žˆ๋„๋ก ๊ธฐ๋Šฅ ์ถ”๊ฐ€
    • ์นด์นด์˜คํ†ก ๊ณต์œ ํ•˜๊ธฐ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์ถ”๊ฐ€ํ•˜์—ฌ ๊ณต์œ  ๊ธฐ๋Šฅ ๊ตฌํ˜„
    • ์ƒํ’ˆ ๋ฆฌ์ŠคํŠธ๋ฅผ ๊น”๋”ํ•˜๊ฒŒ ๋ณผ ์ˆ˜ ์žˆ๋„๋ก Swiper ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์‚ฌ์šฉํ•˜์—ฌ ์บ๋Ÿฌ์…€๋กœ ๊ตฌํ˜„
    • ๊ฒŒ์‹œ๋ฌผ ๋ชฉ๋ก์„ ์ œํ•œ ์—†์ด ๋ณผ ์ˆ˜ ์žˆ๋„๋ก ํŽ˜์ด์ง€ ๋ฌดํ•œ์Šคํฌ๋กค ๊ตฌํ˜„
  • ๊ฒŒ์‹œ๊ธ€ ๋ชจ๋‹ฌ ๊ด€๋ จ ๊ธฐ๋Šฅ ๊ตฌํ˜„
    • ๊ฒŒ์‹œ๊ธ€ ์‚ญ์ œ / ์‹ ๊ณ  ๊ธฐ๋Šฅ
      • ๋‚˜์˜ ๊ฒŒ์‹œ๋ฌผ์ผ๋•Œ๋Š” ์ˆ˜์ • ๋ฐ ์‚ญ์ œ ๊ธฐ๋Šฅ / ๋‹ค๋ฅธ ์‚ฌ์šฉ์ž์˜ ๊ฒŒ์‹œ๋ฌผ์ผ๋•Œ๋Š” ์‹ ๊ณ  ๊ธฐ๋Šฅ ๋ณด์ด๋„๋ก ๊ตฌํ˜„
  • ๊ฒŒ์‹œ๋ฌผ ์ข‹์•„์š” ๊ธฐ๋Šฅ ๊ตฌํ˜„

๐Ÿฆ’ ๊น€์˜ํ˜ธ

๐ŸŽจย ํ™”๋ฉด ๊ฐœ๋ฐœ

  • ๊ฒŒ์‹œ๊ธ€, ์ƒํ’ˆ ์ปดํฌ๋„ŒํŠธ ์ œ์ž‘
  • ๋กœ๊ทธ์ธ ๋ฉ”์ธ, ํ”„๋กœํ•„ ์„ค์ •, ํ”„๋กœํ•„ ์ˆ˜์ •, ์ƒํ’ˆ ๋“ฑ๋ก, ์ƒํ’ˆ ์ˆ˜์ • ํŽ˜์ด์ง€ ํผ๋ธ”๋ฆฌ์‹ฑ

๐Ÿ”งย ๊ธฐ๋Šฅ ๊ฐœ๋ฐœ

  • ํšŒ์›๊ฐ€์ž… ๊ธฐ๋Šฅ ๊ตฌํ˜„
    • ํ”„๋กœํ•„ ์ด๋ฏธ์ง€ ๋ฏธ๋ฆฌ๋ณด๊ธฐ ๊ธฐ๋Šฅ
    • ์ด๋ฏธ์ง€๋ฆฌ์‚ฌ์ด์ง•์„ ํ†ตํ•œ 10MB ์ด์ƒ์˜ ํ”„๋กœํ•„ ์ด๋ฏธ์ง€๋„ ์—…๋กœ๋“œ ๊ฐ€๋Šฅ / ์„ฑ๋Šฅ ํ–ฅ์ƒ
    • ํšŒ์›๊ฐ€์ž… ์ •๋ณด ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ
      • API ๋ช…์„ธ์— ๋”ฐ๋ฅธ ๊ณ„์ • ID ์ค‘๋ณต ๊ฒ€์‚ฌ
      • ์ •๊ทœํ‘œํ˜„์‹์„ ํ†ตํ•œ ๊ณ„์ • ID ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ
    • ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ๋ฅผ ํ†ตํ•œ ์‹œ์ž‘ํ•˜๊ธฐ ๋ฒ„ํŠผ ํ™œ์„ฑํ™”
    • ๋ชจ๋“  ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ ํ†ต๊ณผ ํ›„, Enter ์ž…๋ ฅ ์‹œ ์‹œ์ž‘ํ•˜๊ธฐ ๋ฒ„ํŠผ ํด๋ฆญ๊ณผ ๋™์ผํ•œ ๊ธฐ๋Šฅ
    • API ๋ช…์„ธ์— ๋”ฐ๋ผ ํ”„๋กœํ•„ ์„ค์ • ์ด์ „์— ๋ฐ›์•„์˜จ email, password์™€ ํ•จ๊ป˜ ์„œ๋ฒ„์— ๋ฐ์ดํ„ฐ ์ „์†ก
  • ํ”„๋กœํ•„ ์ˆ˜์ • ๊ธฐ๋Šฅ ๊ตฌํ˜„
    • ๊ธฐ์กด ํ”„๋กœํ•„ ์ •๋ณด ๋ถˆ๋Ÿฌ์˜ค๊ธฐ (ํ”„๋กœํ•„ ์ด๋ฏธ์ง€ ๋ฏธ๋ฆฌ๋ณด๊ธฐ ํฌํ•จ)
    • ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ
      • API ๋ช…์„ธ์— ๋”ฐ๋ฅธ ๊ณ„์ • ID ์ค‘๋ณต ๊ฒ€์‚ฌ (๊ธฐ์กด ID ์œ ์ง€ ์‹œ ์ค‘๋ณต ๊ฒ€์‚ฌ X)
      • ์ •๊ทœํ‘œํ˜„์‹์„ ํ†ตํ•œ ๊ณ„์ • ID ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ
    • ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ๋ฅผ ํ†ตํ•œ ์ €์žฅ ๋ฒ„ํŠผ ํ™œ์„ฑํ™”
    • ํšŒ์›๊ฐ€์ž…์˜ ํ”„๋กœํ•„ ์„ธํŒ…๊ณผ ๋™์ผํ•œ ๊ธฐ๋Šฅ ํฌํ•จ
  • ์ƒํ’ˆ ๊ด€๋ จ ๊ธฐ๋Šฅ ๊ตฌํ˜„
    • ์ƒํ’ˆ ๋“ฑ๋ก
      • ์ด๋ฏธ์ง€๋ฆฌ์‚ฌ์ด์ง•์„ ํ†ตํ•œ 10MB ์ด์ƒ์˜ ์ƒํ’ˆ ์ด๋ฏธ์ง€๋„ ์—…๋กœ๋“œ ๊ฐ€๋Šฅ / ์„ฑ๋Šฅ ํ–ฅ์ƒ
      • ๊ฐ ์ƒํ’ˆ ์ •๋ณด์˜ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ
      • ์ƒํ’ˆ ๊ฐ€๊ฒฉ์˜ ์ฒœ ๋‹จ์œ„ ์ฝค๋งˆ ์ž๋™ ์ƒ์„ฑ & ์‚ญ์ œ
    • ์‚ญ์ œ
      • ์ƒํ’ˆ ์‚ญ์ œ ํด๋ฆญ ์‹œ ์ƒํ’ˆ์ด ์‚ญ์ œ ๋˜๊ณ , ํŒ๋งค ์ค‘์ธ ์ƒํ’ˆ๋งŒ ๋ฆฌ๋ Œ๋”๋ง
    • ์ˆ˜์ •
      • ๊ธฐ์กด ์ƒํ’ˆ ์ •๋ณด ๋ถˆ๋Ÿฌ์˜ค๊ธฐ (์ƒํ’ˆ ์ด๋ฏธ์ง€ ๋ฏธ๋ฆฌ๋ณด๊ธฐ ํฌํ•จ)
      • ์ƒํ’ˆ ๋“ฑ๋ก๊ณผ ๋™์ผํ•œ ๊ธฐ๋Šฅ ํฌํ•จ
    • ์›น์‚ฌ์ดํŠธ์—์„œ ์ƒํ’ˆ ๋ณด๊ธฐ
      • ๋‚ด ์ƒํ’ˆ์— ๋Œ€ํ•ด ์›น์‚ฌ์ดํŠธ์—์„œ ์ƒํ’ˆ ๋ณด๊ธฐ ํด๋ฆญ ์‹œ, ํ•ด๋‹น ํŽ˜์ด์ง€๊ฐ€ ์ƒˆ ์ฐฝ์œผ๋กœ ์—ด๋ฆผ

๐Ÿฃ ๋ฐฐ์Šน์—ฐ

๐Ÿท๏ธ ํ”„๋กœ์ ํŠธ ์ฃผ๋„


๐Ÿ’„ย ๋””์ž์ธ

  • ๊ฐ€์ ธ๋„๋Œ•๋ƒฅ ๋กœ๊ณ ,ย ๋งˆ์Šค์ฝ”ํŠธ ์บ๋ฆญํ„ฐย ๋“ฑ ๋””์ž์ธ ์—์…‹ ์ œ์ž‘
  • ์ง‘์‚ฌ์ƒํ™œ ๋ฉ”์ธ, ์‚ฐ์ฑ… ๋‚œ์ด๋„, ๋™๋ฌผ๋ณ‘์› ํŽ˜์ด์ง€ Figma ์‹œ์•ˆ ์ œ์ž‘

๐ŸŽจย ํ™”๋ฉด ๊ฐœ๋ฐœ

  • ์• ๋‹ˆ๋ฉ”์ด์…˜, ๋กœ๋”ฉ, ๊ฒ€์ƒ‰, ํŒ”๋กœ์šฐ, ๋ชจ๋‹ฌ, ๋ฉ”์ธ ๋ ˆ์ด์•„์›ƒ ์ปดํฌ๋„ŒํŠธ ์ œ์ž‘
  • ์ด๋ฉ”์ผ ๋กœ๊ทธ์ธ, ํŒ”๋กœ์šฐ ํŽ˜์ด์ง€, ์ง‘์‚ฌ์ƒํ™œ ๋ฉ”์ธ, ์‚ฐ์ฑ… ๋‚œ์ด๋„, ๋™๋ฌผ๋ณ‘์› ํŽ˜์ด์ง€ ํผ๋ธ”๋ฆฌ์‹ฑ
  • ์—ฌ๋Ÿฌ ํŽ˜์ด์ง€์—์„œ ๋ฐ˜๋ณต ์‚ฌ์šฉ ๋˜๋Š” ๋ ˆ์ด์•„์›ƒ์„ ์žฌ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•˜๋„๋ก ์ปจํ…์ธ  ๋ ˆ์ด์•„์›ƒ ์ปดํฌ๋„ŒํŠธ๋กœ ๋ถ„๋ฆฌ

๐Ÿ”งย ๊ธฐ๋Šฅ ๊ฐœ๋ฐœ

  • ๋กœ๊ทธ์ธ ๊ธฐ๋Šฅ ๊ตฌํ˜„ (API ๋ช…์„ธ์— ๋”ฐ๋ฆ„)
    • ์ด๋ฉ”์ผ ๋ฐ ๋น„๋ฐ€๋ฒˆํ˜ธ ์œ ํšจ์„ฑ ๊ฒ€์ฆ
    • ์œ ํšจ์„ฑ ๊ฒ€์ฆ์„ ํ†ต๊ณผํ•ด์•ผ ๋กœ๊ทธ์ธ ๋ฒ„ํŠผ ํ™œ์„ฑํ™”
    • ๋กœ์ปฌ ์Šคํ† ๋ฆฌ์ง€์— ํ† ํฐ ์ €์žฅ
  • ๋กœ๊ทธ์•„์›ƒ ๊ธฐ๋Šฅ ๊ตฌํ˜„
    • ๋กœ์ปฌ ์Šคํ† ๋ฆฌ์ง€์— ์ €์žฅ๋œ ํ† ํฐ ์‚ญ์ œ
  • ํŒ”๋กœ์šฐ ๊ธฐ๋Šฅ ๊ตฌํ˜„
    • ํŒ”๋กœ์›Œ / ํŒ”๋กœ์ž‰ ๋ชฉ๋ก ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ›์•„ ํ™”๋ฉด์— ํ‘œ์‹œํ•˜๋Š” ๊ธฐ๋Šฅ ๊ตฌํ˜„ (API ๋ช…์„ธ์— ๋”ฐ๋ฆ„)
    • ํŒ”๋กœ์šฐ / ์–ธํŒ”๋กœ์šฐ ๊ธฐ๋Šฅ ๊ตฌํ˜„ (API ๋ช…์„ธ์— ๋”ฐ๋ฆ„)
  • ์ง‘์‚ฌ์ƒํ™œ ๋ฉ”์ธ ํŽ˜์ด์ง€ ๊ธฐ๋Šฅ ๊ตฌํ˜„
    • Swiper ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์ด์šฉํ•œ ํŽ˜์ด์ง€๋„ค์ด์…˜ ์บ๋Ÿฌ์…€ ๊ตฌํ˜„
    • ์ถ”์ฒœ๊ธ€ ๋ชฉ๋ก
      • ์ถ”์ฒœ๊ธ€ API๊ฐ€ ๋”ฐ๋กœ ์ฃผ์–ด์ง€์ง€ ์•Š์Œ์— ๋”ฐ๋ผ ๊ฒŒ์‹œ๊ธ€๋“ค์ด ์ถ”์ฒœ๊ธ€ ๋ชฉ๋ก์ฒ˜๋Ÿผ ๋ณด์ด๋„๋ก ์‘๋‹ต ๋ฐ์ดํ„ฐ ๊ฐ€๊ณต
    • ์‚ฌ์šฉ์ž๊ฐ€ ๋งŽ์€ ์–‘์˜ ๊ฒŒ์‹œ๊ธ€์„ ํŽธ๋ฆฌํ•˜๊ฒŒ ๋ณผ ์ˆ˜ ์žˆ๋„๋ก ๋ฌดํ•œ์Šคํฌ๋กค ์ ์šฉ
  • ์‚ฐ์ฑ… ๋‚œ์ด๋„ ํŽ˜์ด์ง€ ๊ธฐ๋Šฅ ๊ตฌํ˜„
    • ํ–‰์ •๊ตฌ, ๋‚ ์”จ, ๋ฏธ์„ธ๋จผ์ง€ ์กฐํšŒ ๊ธฐ๋Šฅ
      • Geolocation API๋ฅผ ์ด์šฉํ•ด ์‚ฌ์šฉ์ž์˜ ํ˜„์žฌ ์ขŒํ‘œ๋ฅผ ๊ฐ€์ ธ์˜ด
      • Kakao API๋ฅผ ์ด์šฉํ•ด ํ–‰์ •๊ตฌ์—ญ ์ •๋ณด๋ฅผ ๋ฐ›์•„์˜ด
      • OpenWeatherMap API๋ฅผ ์ด์šฉํ•ด ๋‚ ์”จ, ๋ฏธ์„ธ๋จผ์ง€ ์ •๋ณด๋ฅผ ๋ฐ›์•„์˜ด
    • ์‚ฐ์ฑ… ๋‚œ์ด๋„ ์ฑ…์ •
  • ๋™๋ฌผ๋ณ‘์› ํŽ˜์ด์ง€ ๊ธฐ๋Šฅ ๊ตฌํ˜„
    • Kakao API๋ฅผ ์ด์šฉํ•ด ๊ทผ์ฒ˜ ๋™๋ฌผ๋ณ‘์› ์ •๋ณด๋ฅผ ๊ฐ€๊นŒ์šด ์ˆœ์œผ๋กœ ๋ฐ›์•„์˜ด
    • ์‚ฌ์šฉ์ž๊ฐ€ ์›ํ•˜๋Š” ์ •๋ณด๋งŒ ์„ ๋ณ„์ ์œผ๋กœ ๋ณผ ์ˆ˜ ์žˆ๋„๋ก ๋”๋ณด๊ธฐ ๋ฒ„ํŠผ ์ ์šฉ

๐Ÿงฉย ๊ธฐํƒ€

  • ์‚ฌ์šฉ์ž ์ธ์ฆ ์—ฌ๋ถ€์— ๋”ฐ๋ฅธ ๋ผ์šฐํ„ฐ ์ ‘๊ทผ์ œํ•œ ๊ธฐ๋Šฅ ๊ตฌํ˜„
  • ์žฌ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ์ฝ”๋“œ๋Š” Custom Hook์œผ๋กœ ๋ถ„๋ฆฌ
  • ์ „์—ญ์—์„œ ํ•„์š”ํ•œ ๋ฐ์ดํ„ฐ๋Š” Context ๊ฐ์ฒด๋กœ ๊ด€๋ฆฌ

๐ŸŒธ ์ด๊ด‘๋ ฌ

๐ŸŽจ ํ™”๋ฉด ๊ฐœ๋ฐœ

  • ๋ฒ„ํŠผ ์ปดํฌ๋„ŒํŠธ(S, MS, M, L ์‚ฌ์ด์ฆˆ) ์ œ์ž‘
  • ํšŒ์›๊ฐ€์ž…, ๊ฒ€์ƒ‰, ๊ฒŒ์‹œ๊ธ€ ์ƒ์„ธ, ๊ฒŒ์‹œ๊ธ€ ๋“ฑ๋ก, ๊ฒŒ์‹œ๊ธ€ ์ˆ˜์ •, ์ฑ„ํŒ…๋ฐฉ ๋ชฉ๋ก, ์ฑ„ํŒ… ํŽ˜์ด์ง€ ํผ๋ธ”๋ฆฌ์‹ฑ
  • ์•„์ด์ฝ˜, ์ด๋ฏธ์ง€๋ฅผ ์ „์—ญ์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ๊ณตํ†ต ํŒŒ์ผ ์ œ์ž‘

๐Ÿ”ง ๊ธฐ๋Šฅ ๊ฐœ๋ฐœ

  • ํšŒ์›๊ฐ€์ž… ๊ธฐ๋Šฅ ๊ตฌํ˜„
    • ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ๋ฅผ ํ†ต๊ณผํ•œ ์ด๋ฉ”์ผ๊ณผ ๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ ํ”„๋กœํ•„ ์„ค์ •ํŽ˜์ด์ง€์— props๋กœ ๋‚ด๋ ค์คŒ
    • ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ๋ฅผ ํ†ต๊ณผํ•œ ์ด๋ฉ”์ผ๊ณผ ๋น„๋ฐ€๋ฒˆํ˜ธ๊ฐ€ ์กด์žฌํ•˜๋ฉด, ๋ฒ„ํŠผ์ด ํ™œ์„ฑํ™” ๋˜๋„๋ก ๊ตฌํ˜„
  • ์œ ์ € ๊ฒ€์ƒ‰ ๊ธฐ๋Šฅ ๊ตฌํ˜„
    • ์‚ฌ์šฉ์ž ์ž…๋ ฅ๊ฐ’์ด ๋ฐ”๋€” ๋•Œ ๋งˆ๋‹ค ์ž…๋ ฅ๊ฐ’๊ณผ ์ผ์น˜ํ•˜๋Š” ์œ ์ € ๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ ๊ตฌํ˜„
    • ๊ฒ€์ƒ‰๋œ ์‚ฌ์šฉ์ž ํด๋ฆญ ์‹œ ํ•ด๋‹น ์‚ฌ์šฉ์ž์˜ ํ”„๋กœํ•„๋กœ ์ด๋™ํ•˜๋Š” ๋งํฌ ๊ตฌํ˜„
    • ์‚ฌ์šฉ์ž ID๊ฐ€ ์•„๋‹Œ, ์‚ฌ์šฉ์ž ์ด๋ฆ„ ๊ณผ input ์ฐฝ์— ์ž…๋ ฅํ•œ ํ‚ค์›Œ๋“œ๊ฐ€ ๋™์ผํ•œ ๋ถ€๋ถ„์ด ์žˆ๋Š” ๊ฒฝ์šฐ์—๋Š” ์ž…๋ ฅํ•œ ํ‚ค์›Œ๋“œ ๋ถ€๋ถ„๋งŒ ๋‹ค๋ฅธ ์Šคํƒ€์ผ ์ ์šฉํ•˜์—ฌ ๊ฐ•์กฐ
  • ๊ฒŒ์‹œ๊ธ€ ๊ด€๋ จ ๊ธฐ๋Šฅ ๊ตฌํ˜„ ( ์กฐํšŒ, ๋“ฑ๋ก, ์ˆ˜์ •, ์‚ญ์ œ, ์‹ ๊ณ  )
    • ์‚ฌ์šฉ์ž ์ž…๋ ฅ ํ…์ŠคํŠธ์™€ ์ด๋ฏธ์ง€ ํŒŒ์ผ ๊ฒŒ์‹œ๋ฌผ ์—…๋กœ๋“œ ๊ธฐ๋Šฅ ๊ตฌํ˜„
    • ํ…์ŠคํŠธ์™€ ์ด๋ฏธ์ง€๊ฐ€ ์—†์„๊ฒฝ์šฐ, ๋ฒ„ํŠผ ๋น„ํ™œ์„ฑํ™”
    • ์ด๋ฏธ์ง€ ํŒŒ์ผ 3๊ฐœ ์ดˆ๊ณผ ์‹œ ์‚ฌ์šฉ์ž์—๊ฒŒ ๋ณด์—ฌ์ง€๋Š” alert ๊ตฌํ˜„
    • ํฌ์ŠคํŠธ ํ•  ์ด๋ฏธ์ง€ ๋ฏธ๋ฆฌ๋ณด๊ธฐ ๋ฐ ๋ฏธ๋ฆฌ๋ณด๊ธฐ์—์„œ ์‚ญ์ œ ๊ธฐ๋Šฅ ๊ตฌํ˜„
    • ํฌ์ŠคํŠธ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ›์•„ ํ™”๋ฉด์— ๊ทธ๋ ค์ฃผ๋Š” ๊ธฐ๋Šฅ ๊ตฌํ˜„ (API ๋ช…์„ธ์— ๋”ฐ๋ฆ„)
    • ๊ฒŒ์‹œ๋ฌผ ์ˆ˜์ • ๊ธฐ๋Šฅ์„ ๊ตฌํ˜„
  • ๋Œ“๊ธ€ ๊ด€๋ จ ๊ธฐ๋Šฅ ๊ตฌํ˜„ ( ์กฐํšŒ, ๋“ฑ๋ก, ์‚ญ์ œ, ์‹ ๊ณ  )
    • ๋Œ“๊ธ€ ๋ชฉ๋ก ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ›์•„ ํ™”๋ฉด์— ๊ทธ๋ ค์ฃผ๋Š” ๊ธฐ๋Šฅ ๊ตฌํ˜„ (API ๋ช…์„ธ์— ๋”ฐ๋ฆ„)
    • ๋Œ“๊ธ€ ์—…๋กœ๋“œ,์‚ญ์ œ ๋ฐ ์‹ ๊ณ  ๊ธฐ๋Šฅ ๊ตฌํ˜„ (API ๋ช…์„ธ์— ๋”ฐ๋ฆ„)
  • ์ฑ„ํŒ… ๊ด€๋ จ ๊ธฐ๋Šฅ ๊ตฌํ˜„
    • ์ฑ„ํŒ… ๋ชฉ๋ก ์กฐํšŒ ๊ธฐ๋Šฅ

      ์ฑ„ํŒ… ๊ธฐ๋Šฅ
      • ์ฑ„ํŒ… ๊ธฐ๋Šฅ ๋ฐฉ์‹

      ๋กœ๊ทธ์ธ๋œ ์‚ฌ์šฉ์ž โ†”ย ์ฑ„ํŒ…๋ฐฉ์œผ๋กœ ์‚ฌ์šฉ๋  ์ œ 3์ž์˜ ๊ฒŒ์‹œ๊ธ€ โ†”ย ์ฑ„ํŒ…ํ•  ์ƒ๋Œ€ ์‚ฌ์šฉ์ž

      โ†’ ์ฑ„ํŒ…๋ฐฉ์œผ๋กœ ์‚ฌ์šฉ๋  ์ œ 3์ž์˜ ์•„์ด๋””๋Š” ์œ ์ € ๊ฒ€์ƒ‰์„ ํ†ตํ•˜์—ฌ ์ฐพ์„ ์ˆ˜ ์—†๋„๋ก ์„ค์ •

      < ์ฑ„ํŒ…๋ฐฉ ์ƒ์„ฑ >

      1. ์ฑ„ํŒ…ํ•  ์ƒ๋Œ€ ์‚ฌ์šฉ์ž์˜ ํ”„๋กœํ•„์—์„œ ์ฑ„ํŒ… ์ด๋ฏธ์ง€ ๋ฒ„ํŠผ์„ ํด๋ฆญํ•˜๋ฉด, ์ฑ„ํŒ…๋ฐฉ์œผ๋กœ ์‚ฌ์šฉ๋  ์ œ 3์ž์˜ ๊ฒŒ์‹œ๊ธ€์ด ์ƒ์„ฑ๋œ๋‹ค.
       // ์ œ 3์ž์˜ ๊ฒŒ์‹œ๊ธ€์„ ๋‹ค๋ฅธ ์œ ์ €๊ฐ€ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ๋„๋ก ํ† ํฐ๊ฐ’์„ ์ง€์ •
       const CHAT_TOKEN = process.env.REACT_APP_CHAT_SERVER_TOKEN;
      1. ์ œ 3์ž์˜ ๊ฒŒ์‹œ๊ธ€์— ์ „์†ก๋˜๋Š” ์ปจํ…์ธ ์ธ ์ฑ„ํŒ… ๋ฐ์ดํ„ฐ โ†’ โ€˜๋กœ๊ทธ์ธ๋œ ์‚ฌ์šฉ์ž์˜ accountname,์ฑ„ํŒ…ํ•  ์ƒ๋Œ€ ์‚ฌ์šฉ์ž์˜ accountnameโ€™
       const createChatroom = () => {
           axios
             .post(
       	`https://mandarin.api.weniv.co.kr/post`,
       	{
       	  post: {
       	    content: `${userAccountname},${profileUserAccountname}`,
       	    image: '',
       	  },
       	},
       	{
       	  headers: {
       	    Authorization: `Bearer ${CHAT_TOKEN}`,
       	    'Content-type': 'application/json',
       	  },
       	},
             )
             .then((res) => {
       	navigate(`/chat/${res.data.post.id}`);
             });
         };

      โ†’ ์ „์†ก๋œ ๋ฐ์ดํ„ฐ๋Š” ์ฑ„ํŒ…๋ฆฌ์ŠคํŠธ๋ฅผ ๋ถˆ๋Ÿฌ์˜ฌ๋•Œ์™€ ์ฑ„ํŒ…๋ฐฉ ์ด๋ฆ„์„ ๋‚˜ํƒ€๋‚ผ๋•Œ ์‚ฌ์šฉํ•œ๋‹ค.

      1. ์ฑ„ํŒ…๋ฐฉ ์ƒ์„ฑ์‹œ, ์ œ 3์ž์˜ ๊ฒŒ์‹œ๊ธ€์˜ content ๋‚ด์šฉ๊ณผ ์ƒ์„ฑํ•  content ๋‚ด์šฉ์ด ์ค‘๋ณต๋œ๋‹ค๋ฉด alert ์ฐฝ์„ ๋„์›Œ์„œ ์ด๋ฏธ ์กด์žฌํ•˜๋Š” ์ฑ„ํŒ…๋ฃธ์ด๋ผ๋Š” ์‚ฌ์‹ค์„ ์‚ฌ์šฉ์ž์—๊ฒŒ ์•Œ๋ฆฐ๋‹ค.

      < ์ฑ„ํŒ…๋ฐฉ ๋ฆฌ์ŠคํŠธ >

      • ์ œ 3์ž์˜ ๊ฒŒ์‹œ๊ธ€์˜ ์ •๋ณด๋ฅผ ๋ถˆ๋Ÿฌ์™€, ์ „์†ก๋œ ์ปจํ…์ธ  ๋ฐ์ดํ„ฐ ์— ์‚ฌ์šฉ์ž์˜ accountname ์ด ํฌํ•จ๋œ ๊ฒŒ์‹œ๊ธ€๋งŒ ๋ณด์—ฌ์ค€๋‹ค.

      < ์ฑ„ํŒ…๋ฐฉ >

      • useParams() ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ, ์„ ํƒํ•œ url์˜ ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜จ ํ›„, ๊ทธ ํŒŒ๋ผ๋ฏธํ„ฐ(postid) ์— ํ•ด๋‹นํ•˜๋Š” ๊ฒŒ์‹œ๊ธ€์„ ๋ถˆ๋Ÿฌ์˜จ๋‹ค. ์—ฌ๊ธฐ์— ์ž‘์„ฑ๋œ ๋Œ“๊ธ€์ด ๋ณธ์ธ์˜ ๊ฒƒ์ด๋ผ๋ฉด, ๋ณธ์ธ์ด ๋‚ ๋ฆฐ ์ฑ„ํŒ…์œผ๋กœ ๋ณด์—ฌ์ง€๊ณ , ์•„๋‹ˆ๋ผ๋ฉด ํƒ€ ์‚ฌ์šฉ์ž๊ฐ€ ๋ณด๋‚ธ ์ฑ„ํŒ…์ฒ˜๋Ÿผ ๋ณด์—ฌ์ง„๋‹ค.

      < ์ฑ„ํŒ… >

      • ์ฑ„ํŒ…๋ฐฉ์— ์ž…์žฅํ•˜๋ฉด, ์ฑ„ํŒ…๋ฐฉ์œผ๋กœ ์‚ฌ์šฉ๋œ ๊ฒŒ์‹œ๋ฌผ์— ๋Œ“๊ธ€ ํ˜•์‹์œผ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ์ „์†กํ•œ๋‹ค.

(Top)


10. ํŽ˜์ด์ง€ ์บก์ณ

1) ํ™ˆ

์‹œ์ž‘ ํ™”๋ฉด ํšŒ์›๊ฐ€์ž… ํŽ˜์ด์ง€ ๋กœ๊ทธ์ธ ํŽ˜์ด์ง€
splash ํšŒ์›๊ฐ€์ž… ๋กœ๊ทธ์ธ
ํ”ผ๋“œ ํŽ˜์ด์ง€ ๊ฒ€์ƒ‰ ํŽ˜์ด์ง€ 404 ํŽ˜์ด์ง€
แ„‘แ…ตแ„ƒแ…ณ แ„€แ…ฅแ†ทแ„‰แ…ขแ†จ 404

2) ์ฑ„ํŒ…

์ฑ„ํŒ… ๋ชฉ๋ก ํŽ˜์ด์ง€ ์ฑ„ํŒ…๋ฐฉ ํŽ˜์ด์ง€ ์ฑ„ํŒ…๋ฐฉ ๋‚˜๊ฐ€๊ธฐ
แ„Žแ…ฌแ„Œแ…ฉแ†ผ_แ„Žแ…ขแ„แ…ตแ†ผแ„…แ…ฎแ†ทแ„…แ…ตแ„‰แ…ณแ„แ…ณ_AdobeExpress แ„Žแ…ฌแ„Œแ…ฉแ†ผ_แ„Žแ…ขแ„แ…ตแ†ผแ„แ…ฉแ„†แ…ฆแ†ซแ„แ…ณ_AdobeExpress แ„Žแ…ขแ„แ…ตแ†ผแ„‡แ…กแ†ผแ„‚แ…กแ„€แ…กแ„€แ…ต_AdobeExpress

3) ๊ฒŒ์‹œ๊ธ€

๊ฒŒ์‹œ๊ธ€ ์ƒ์„ธ ํŽ˜์ด์ง€ ๊ฒŒ์‹œ๊ธ€ ์ž‘์„ฑ ํŽ˜์ด์ง€ ๊ฒŒ์‹œ๊ธ€ ์ˆ˜์ • ํŽ˜์ด์ง€
แ„€แ…ฆแ„‰แ…ตแ„†แ…ฎแ†ฏแ„‰แ…กแ†ผแ„‰แ…ฆ แ„€แ…ฆแ„‰แ…ตแ„†แ…ฎแ†ฏแ„Œแ…กแ†จแ„‰แ…ฅแ†ผ แ„€แ…ฆแ„‰แ…ตแ„†แ…ฎแ†ฏแ„‰แ…ฎแ„Œแ…ฅแ†ผ
๊ฒŒ์‹œ๊ธ€ ์‚ญ์ œ ๊ฒŒ์‹œ๊ธ€ ์‹ ๊ณ  ๋Œ“๊ธ€ ๊ธฐ๋Šฅ
แ„Žแ…ฌแ„Œแ…ฉแ†ผ_แ„€แ…ฆแ„‰แ…ตแ„€แ…ณแ†ฏแ„‰แ…กแ†จแ„Œแ…ฆ_AdobeExpress แ„Žแ…ฌแ„Œแ…ฉแ†ผ_แ„€แ…ฆแ„‰แ…ตแ„€แ…ณแ†ฏแ„‰แ…ตแ†ซแ„€แ…ฉ_AdobeExpress แ„Žแ…ฌแ„Œแ…ฉแ†ผ_แ„€แ…ฆแ„‰แ…ตแ„†แ…ฎแ†ฏแ„ƒแ…ขแ†บแ„€แ…ณแ†ฏ_AdobeExpress

4) ํ”„๋กœํ•„

๋งˆ์ด ํ”„๋กœํ•„ ํŽ˜์ด์ง€ ์œ ์–ด ํ”„๋กœํ•„ ํŽ˜์ด์ง€ ๋ฆฌ์ŠคํŠธํ˜•/์•จ๋ฒ”ํ˜• ๋ณด๊ธฐ
แ„†แ…กแ„‹แ…ต แ„‘แ…ณแ„…แ…ฉแ„‘แ…ตแ†ฏ แ„‹แ…ฒแ„‹แ…ฅแ„‘แ…ณแ„…แ…ฉแ„‘แ…ตแ†ฏ แ„‹แ…ขแ†ฏแ„‡แ…ฅแ†ทแ„’แ…งแ†ผแ„…แ…ตแ„‰แ…ณแ„แ…ณแ„’แ…งแ†ผ
ํ”„๋กœํ•„ ์ˆ˜์ • ํŽ˜์ด์ง€ ํŒ”๋กœ์›Œ/ํŒ”๋กœ์ž‰ ํŽ˜์ด์ง€ ๋กœ๊ทธ์•„์›ƒ ๊ธฐ๋Šฅ
ํ”„๋กœํ•„ ์ˆ˜์ • แ„‘แ…กแ†ฏแ„…แ…ฉแ„‹แ…ฎแ„‘แ…ฆแ„‹แ…ตแ„Œแ…ต แ„…แ…ฉแ„€แ…ณแ„‹แ…กแ„‹แ…ฎแ†บ

5) ํŒ๋งค ์ƒํ’ˆ

์ƒํ’ˆ ๋“ฑ๋ก ํŽ˜์ด์ง€ & ์ƒํ’ˆ ๋งํฌ ์ด๋™ ์ƒํ’ˆ ์ˆ˜์ • ํŽ˜์ด์ง€ ์ƒํ’ˆ ์‚ญ์ œ ํŽ˜์ด์ง€
์ƒํ’ˆ ๋“ฑ๋ก ๋ฐ ํŒ๋งค ์‚ฌ์ดํŠธ ์ด๋™ ์ƒํ’ˆ ์ˆ˜์ • ์ƒํ’ˆ ์‚ญ์ œ

6) ์ง‘์‚ฌ์ƒํ™œ

์ง‘์‚ฌ์ƒํ™œ ๋ฉ”์ธ ํŽ˜์ด์ง€ ์‚ฐ์ฑ… ๋‚œ์ด๋„ ํŽ˜์ด์ง€ ๋™๋ฌผ๋ณ‘์› ํŽ˜์ด์ง€
แ„†แ…ฆแ„‹แ…ตแ†ซ แ„‰แ…กแ†ซแ„Žแ…ขแ†จ แ„‚แ…กแ†ซแ„‹แ…ตแ„ƒแ…ฉ แ„†แ…ฆแ„‹แ…ตแ†ซ แ„ƒแ…ฉแ†ผแ„†แ…ฎแ†ฏแ„‡แ…งแ†ผแ„‹แ…ฏแ†ซ

(Top)


11. ํ•ต์‹ฌ ๊ธฐ๋Šฅ ๋ฐ ์ฝ”๋“œ ์„ค๋ช…

๐Ÿฐ ๊น€๋ฏผ์Šน

์‚ฌ์šฉ์ž์˜ ํ”„๋กœํ•„ ํŽ˜์ด์ง€
useEffect(() => {
    if (location.pathname === `/profile/${userAccountname}`) {
      navigate('/profile');
    }
  }, [location, userAccountname, navigate]);
  • ํ˜„์žฌ url์ด /profile/userAccountname ์ผ ๊ฒฝ์šฐ ๋‚˜์˜ ํ”„๋กœํ•„ ํŽ˜์ด์ง€์ด๋ฏ€๋กœ url ์ฃผ์†Œ๋ฅผ /profile ๋กœ ๋ณ€๊ฒฝํ•˜๋„๋ก ํ•จ

useEffect(() => {
    const getUserProfileInfo = () => {
      axios({
        url: url + `/profile/${accountname ? accountname : userAccountname}`,
        method: 'GET',
        headers: {
          Authorization: `Bearer ${userToken}`,
          'Content-type': 'application/json',
        },
      })
        .then((res) => {
          setUserProfileInfo(res.data.profile);
        })
        .catch((err) => {
          console.error(err);
        });
    };
    getUserProfileInfo();
  }, [url, accountname, userAccountname, userToken]);

์œ ์ € ํ”„๋กœํ•„ ์ •๋ณด๋ฅผ ๋ฐ›์•„์˜ค๋Š” getUserProfileInfo() ํ•จ์ˆ˜

  • accountname(ํ˜„์žฌ ํ”„๋กœํ•„ url์— ํ‘œ์‹œ๋œ ์•„์ด๋””)์™€ userAccountname(ํ˜„์žฌ ๋กœ๊ทธ์ธ๋˜์–ด์žˆ๋Š” ์‚ฌ์šฉ์ž์˜ ์•„์ด๋””) ๊ฐ™์„ ๊ฒฝ์šฐ ๋‚ด ํ”„๋กœํ•„ ์ •๋ณด๋ฅผ ๊ฐ€์ ธ์˜ค๊ณ , ๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด ํ˜„์žฌ URL์˜ ์‚ฌ์šฉ์ž ์•„์ด๋””์—์„œ ๊ทธ ์‚ฌ์šฉ์ž์˜ ํ”„๋กœํ•„ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ค๊ฒŒ ํ•จ.


ํ™ˆ ํ”ผ๋“œ ํŽ˜์ด์ง€, ํ”„๋กœํ•„ ํฌ์ŠคํŠธ ์˜์—ญ ๋ฌดํ•œ์Šคํฌ๋กค ๊ธฐ๋Šฅ
// ๋ฌดํ•œ ์Šคํฌ๋กค ๊ตฌํ˜„์— ํ•„์š”ํ•œ useState
  const [numFeed, setNumFeed] = useState(0);
  const [loading, setLoading] = useState(false);
  const [done, setDone] = useState(false);
  const [ref, inView] = useInView();

// ์„œ๋ฒ„์—์„œ ํ”ผ๋“œ๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” ํ•จ์ˆ˜
  const getUserFeed = useCallback(async () => {
    const option = {
      url: url + `/post/feed/?limit=10&skip=${numFeed}`,
    ...
      },
    };
    setLoading(true);

    await axios(option)
      .then((res) => {
        // ๊ธฐ์กด์˜ ๋ฐ์ดํ„ฐ์™€ ์ƒˆ๋กœ์šด ๋ฐ์ดํ„ฐ ๋ฐฐ์—ด ํ•ฉ์น˜๊ธฐ
        setIsFollowingPost(isFollowingPost.concat(res.data.posts));
        setLoading(false);
        setIsLoading(false);
      })
      .catch((err) => {
        setIsLoading(false);
        console.error(err);
      });
  }, [numFeed]);

  useEffect(() => {
    // ์‚ฌ์šฉ์ž๊ฐ€ ๋งˆ์ง€๋ง‰ ์š”์†Œ๋ฅผ ๋ณด๊ณ ์žˆ๊ณ (inview === true), ๋กœ๋”ฉ์ค‘์ด ์•„๋‹ˆ๋ผ๋ฉด
    if (inView && !loading) {
      setNumFeed((current) => current + 10);
    }
  }, [inView, loading]);

return (
	<div>
	  {isFollowingPost.map((post, i) =>
	    // isFollowingPost์˜ ๋งˆ์ง€๋ง‰ ์š”์†Œ๋ผ๋ฉด ref์ถ”๊ฐ€
	    isFollowingPost.length - 1 === i ? (
	      <div key={post.id} ref={ref} />
	    ) : (
	      <div key={post.id}>
	        <Post post={post} />
	      </div>
	    ),
	  )}
	</div>
)
  • ๊ฒŒ์‹œ๋ฌผ์„ ๊ฐœ์ˆ˜ ์ œํ•œ์—†์ด ๋ณด๊ธฐ ์œ„ํ•ด 'react-intersection-observer' ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์‚ฌ์šฉํ•˜์—ฌ ๋ฌดํ•œ์Šคํฌ๋กค ๊ตฌํ˜„ํ•จ.
  • ์„œ๋ฒ„์—์„œ ํ”ผ๋“œ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” ํ•จ์ˆ˜๋ฅผ axios ๋กœ ๋ถˆ๋Ÿฌ์˜ด. ๋ฐ์ดํ„ฐ๋ฅผ ๋ˆ„์ ํ•ด์„œ ์š”์ฒญํ•˜๋Š” ๋ถˆํ•„์š”ํ•œ ๊ณผ์ •์„ ๋ง‰๊ธฐ ์œ„ํ•ด skip ์กฐ๊ฑด ์ถ”๊ฐ€ํ•œ ํ›„ concat ๋ฉ”์„œ๋“œ๋กœ ๋ฐฐ์—ด ํ•ฉ์ณ์„œ ๋ธŒ๋ผ์šฐ์ €์— ๋ณด์—ฌ์คŒ.
  • ๋ถˆ๋Ÿฌ์˜จ ํฌ์ŠคํŠธ๋“ค์˜ ๋งˆ์ง€๋ง‰ ์š”์†Œ๋ผ๋ฉด, ๋ธŒ๋ผ์šฐ์ € ํ•˜๋‹จ๋ถ€๋ถ„์„ ์˜๋ฏธํ•˜๋Š” ref ๊ฐ’ ์ถ”๊ฐ€ํ•จ. ํ•ด๋‹น ์š”์†Œ๊ฐ€ ๋ณด์ด๋ฉด inView ๊ฐ’์ด ย trueย ๋กœ, ์•ˆ ๋ณด์ด๋ฉดย false๋กœ ์ž๋™์œผ๋กœ ๋ณ€๊ฒฝ๋จ. inView ๊ฐ€ true์ผ ๊ฒฝ์šฐ ์„œ๋ฒ„์— ๊ฒŒ์‹œ๋ฌผ ์ถ”๊ฐ€๋กœ 10๊ฐœ์”ฉ ์š”์ฒญํ•จ.

axios(option).then   
...
if (res.data.posts.length < 10) {
  setDone(true);
}

useEffect(() => {
  // ์ƒˆ๋กœ ๋ฐ›์•„์˜จ ๋ฐ์ดํ„ฐ ๋ฐฐ์—ด ๊ฐœ์ˆ˜๊ฐ€ 10๊ฐœ ๋ฏธ๋งŒ์ผ๋•Œ ์Šคํฌ๋กค ๋ฉˆ์ถ”๊ธฐ
  if (!done) {
    getUserFeed();
  }
}, [numFeed]);
  • ๋ถˆ๋Ÿฌ์˜ค๋Š” ๋ฐ์ดํ„ฐ์˜ ๊ฐ€์žฅ ๋งˆ์ง€๋ง‰ ์š”์†Œ๋ฅผ ๋ณด๊ณ ์žˆ์œผ๋ฉด ๊ณ„์† ์š”์ฒญ๋˜๋Š” ํ˜„์ƒ์„ ๋ง‰๊ธฐ ์œ„ํ•ด, ์ƒˆ๋กœ ๋ฐ›์•„์˜ค๋Š” ๋ฐ์ดํ„ฐ ๊ฐœ์ˆ˜๊ฐ€ 10๊ฐœ ๋ฏธ๋งŒ์ผ๋•Œ donestate๋ฅผ true ๋กœ ๋ณ€๊ฒฝ. done ์ด true์ผ ๊ฒฝ์šฐ ๊ณ„์†ํ•ด์„œ ์š”์ฒญ์„ ๋ฐ›์•„์˜ค๊ณ , false ์ผ๊ฒฝ์šฐ ์š”์ฒญ์„ ๋ฉˆ์ถ”๊ฒŒ ํ•จ.


๊ฒŒ์‹œ๋ฌผ ์ด๋ฏธ์ง€ / ์ƒํ’ˆ ๋ชฉ๋ก ์บ๋Ÿฌ์…€ ๊ธฐ๋Šฅ
{imageFile[0] ? (
  <SwiperWrapper>
    <Swiper
      style={swiperStyle}
      spaceBetween={30}
      pagination={{
        clickable: true,
      }}
      modules={[Pagination]}
      className='mySwiper'
    >
      {imageFile ? (
        imageFile.map((img, i) => (
          <SwiperSlide key={i}>
            <ContentImg src={img} alt='' />
          </SwiperSlide>
        ))
      ) : (
        <></>
      )}
    </Swiper>
  </SwiperWrapper>
  • ๊ฒŒ์‹œ๋ฌผ์— ์—…๋กœ๋“œ๋œ ์ด๋ฏธ์ง€๋“ค์„ Swiper ์บ๋Ÿฌ์…€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์‚ฌ์šฉํ•˜์—ฌ ๊ตฌํ˜„ํ•จ. ์‚ผํ•ญ์—ฐ์‚ฐ์ž๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ด๋ฏธ์ง€ ํŒŒ์ผ์ด ์žˆ์„ ๊ฒฝ์šฐ Swiper๋กœ ์ด๋ฏธ์ง€๋“ค์„ ํ‘œ์‹œํ•ด์ฃผ๊ณ  ์žˆ์Œ.
{itemList.map((item) => (
  <SwiperSlide key={item.id}>
    <Product
      productid={item.id}
      productImg={item.itemImage}
      productName={item.itemName}
      productPrice={`${item.price.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',')} ๋ƒฅ`}
    />
  </SwiperSlide>
  • ์ƒํ’ˆ ๋ชฉ๋ก ๋ฐ์ดํ„ฐ๋ฅผ ๋ถˆ๋Ÿฌ์™€์„œ ์บ๋Ÿฌ์…€๋กœ ๋„˜๊ฒจ ํ™•์ธํ•  ์ˆ˜ ์žˆ๊ฒŒ ๊ตฌํ˜„ํ•จ.

๐Ÿฆ’ ๊น€์˜ํ˜ธ

ํšŒ์›๊ฐ€์ž… ๊ธฐ๋Šฅ (ํ”„๋กœํ•„ ์„ค์ •)
  • ์ด๋ฏธ์ง€ ๋ฆฌ์‚ฌ์ด์ง•์„ ์œ„ํ•œ browser-image-compression ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์‚ฌ์šฉ
    • 10MB ์ด์ƒ์˜ ์ด๋ฏธ์ง€๋„ ์—…๋กœ๋“œ ๊ฐ€๋Šฅ

    • ์ด๋ฏธ์ง€ ๋กœ๋”ฉ ์†๋„ ๊ฐœ์„  ๋“ฑ ์„ฑ๋Šฅ ํ–ฅ์ƒ

      // ์•„๋ž˜์™€ ๊ฐ™์ด ์˜ต์…˜ ๊ฐ’์„ ๋ถ€์—ฌํ•  ์ˆ˜ ์žˆ์Œ
      {
        maxSizeMB: 0.08, // ํŒŒ์ผ ์ตœ๋Œ€ ํฌ๊ธฐ
        maxWidthOrHeight: 320, // ๋„ˆ๋น„ or ๋†’์ด ์ตœ๋Œ“๊ฐ’
      }
    • ๊ธฐ์กด์—๋Š” ์•„๋ž˜์™€ ๊ฐ™์ด 102400B (100KB)๋กœ ์ œํ•œ๋œ ํฌ๊ธฐ๋ณด๋‹ค ์š”์ฒญ์ด ํฌ๋‹ค๋Š” ๋ฉ”์‹œ์ง€๋ฅผ ์‘๋‹ต๋ฐ›์Œ, ํ•ด๋‹น ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ํ†ตํ•ด ๊ธฐ์กด ์ด๋ฏธ์ง€ ํฌ๊ธฐ์˜ 1% ์ˆ˜์ค€์œผ๋กœ ํฌ๊ธฐ๋ฅผ ์ค„์—ฌ ํ•ด๊ฒฐํ•˜์˜€์Œ

    • ๋ฆฌ์‚ฌ์ด์ง• ์ „ / ํ›„ ์ด๋ฏธ์ง€ ํŒŒ์ผ ํฌ๊ธฐ


  • Blob to Base64
    • ์•„๋ž˜์™€ ๊ฐ™์ด ์ด๋ฏธ์ง€ ๋ฆฌ์‚ฌ์ด์ง• ๊ณผ์ •์—์„œ ๋งŒ๋“ค์–ด์ง„ Blob์„ Web API๋ฅผ ํ†ตํ•ด Base64 ํ˜•ํƒœ๋กœ ๋ณ€ํ™˜ํ•˜์—ฌ ์–ด๋””์—์„œ๋“  ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ๋ฌธ์ž์—ด ํ˜•ํƒœ๋กœ ๋งŒ๋“ค์–ด ์คŒ

      // Blob to Base64
      const readerBlob = new FileReader();
      readerBlob.readAsDataURL(compressedFile);
      readerBlob.onloadend = () => {
        if (imageFunction) {
          imageFunction(readerBlob.result); // ์„œ๋ฒ„๋กœ ์ „์†ก๋  ์ด๋ฏธ์ง€
        } else {
          setThumbnailImg(readerBlob.result); // ์ด๋ฏธ์ง€ ๋ฏธ๋ฆฌ๋ณด๊ธฐ
        }
      };
      • ํ•˜์ง€๋งŒ Base64 ํŠน์„ฑ์ƒ ๋ฌธ์ž์—ด์ด ๊ธธ์–ด์ ธ ๊ฐ€๋…์„ฑ์ด ๋–จ์–ด์ง€๋ฉฐ, ์šฉ๋Ÿ‰ ์ด์Šˆ๊ฐ€ ์ƒ๊ธธ ์ˆ˜ ์žˆ์Œ

  • ๊ธฐ๋ณธ ํ”„๋กœํ•„ ์ด๋ฏธ์ง€

    • ์‚ฌ์šฉ์ž๊ฐ€ ํ”„๋กœํ•„ ์ด๋ฏธ์ง€๋ฅผ ๋”ฐ๋กœ ์„ค์ •ํ•˜์ง€ ์•Š์œผ๋ฉด, ๋ฏธ๋ฆฌ Base64๋กœ ์ธ์ฝ”๋”ฉ ํ•ด๋†“์€ ์ด๋ฏธ์ง€๊ฐ€ ์•„๋ž˜์™€ ๊ฐ™์ด ์„œ๋ฒ„๋กœ ์ „์†ก๋จ

  • ์‚ฌ์šฉ์ž ์ด๋ฆ„, ๊ณ„์ • ID, ์†Œ๊ฐœ input ์ฐฝ ์ƒํƒœ๊ด€๋ฆฌ
    • ๊ฐ input ์ฐฝ์— ๋งž๋Š” ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ๋ฅผ ํ†ตํ•ด ์ƒํƒœ๊ด€๋ฆฌ๋ฅผ ํ•˜์˜€์Œ
      • ์‚ฌ์šฉ์ž ์ด๋ฆ„ : 2~10์ž ์ž…๋ ฅ ๊ฐ€๋Šฅ
      • ๊ณ„์ • ID : ์˜๋ฌธ, ์ˆซ์ž, ํŠน์ˆ˜๋ฌธ์ž(. , _ )๋งŒ ์‚ฌ์šฉ ๊ฐ€๋Šฅ
      • ์†Œ๊ฐœ : 1~100์ž ์ž…๋ ฅ ๊ฐ€๋Šฅ

  • ์‹œ์ž‘ํ•˜๊ธฐ ๋ฒ„ํŠผ ์ƒํƒœ๊ด€๋ฆฌ
    • ์•„๋ž˜์™€ ๊ฐ™์ด ๋ชจ๋“  input ์ฐฝ์˜ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ๋ฅผ ๋งŒ์กฑํ–ˆ์„ ๋•Œ, ๋ฒ„ํŠผ์ด ํ™œ์„ฑํ™” ๋˜๋„๋ก ํ•จ

      useEffect(() => {
        if (userName && accountName && intro) {
          setDisabledButton(false);
        } else {
          setDisabledButton(true);
        }
      }, [userName, accountName, intro]);
    • Enter ์ž…๋ ฅ ์‹œ ์‹œ์ž‘ํ•˜๊ธฐ ๋ฒ„ํŠผ ํด๋ฆญ๊ณผ ๋™์ผํ•œ ํšจ๊ณผ๋ฅผ ์คŒ

      const onCheckEnter = (e) => {
        disabledButton === false && e.key === 'Enter' && onClickStartButtonHandler();
      };

  • ํšŒ์› ๊ฐ€์ž…
    • API ๋ช…์„ธ์— ๋”ฐ๋ผ ํ”„๋กœํ•„ ์„ค์ • ์ด์ „์— ๋ฐ›์•„์˜จ email, password์™€ ํ•จ๊ป˜ ์„œ๋ฒ„์— ๋ฐ์ดํ„ฐ ์ „์†ก

      // JoinMembershipInput.jsx์—์„œ ์ „๋‹ฌ๋ฐ›์Œ
      const location = useLocation();
      const email = location.state.email;
      const password = location.state.password;
      const onClickStartButtonHandler = () => {
        const option = {
          url: 'https://mandarin.api.weniv.co.kr/user',
          method: 'POST',
          headers: { 'Content-type': 'application/json' },
          data: {
            user: {
              username: userName,
              email: email,
              password: password,
              accountname: accountName,
              intro: intro,
              image: image,
            },
          },
        };
      };
ํ”„๋กœํ•„ ์ˆ˜์ • ๊ธฐ๋Šฅ
  • ๊ธฐ์กด ํ”„๋กœํ•„ ์ •๋ณด ๋ถˆ๋Ÿฌ์˜ค๊ธฐ (ํ”„๋กœํ•„ ์ด๋ฏธ์ง€ ๋ฏธ๋ฆฌ๋ณด๊ธฐ ํฌํ•จ)

    const getInfo = () => {
          const option = {
            url: 'https://mandarin.api.weniv.co.kr/user/myinfo',
            method: 'GET',
            headers: { Authorization: `Bearer ${userToken}` },
          };
    
          axios(option)
            .then((res) => {
              setUserName(res.data.user.username);
              setDefaultAccountName(res.data.user.accountname);
              setAccountName(res.data.user.accountname);
              setIntro(res.data.user.intro);
              setImage(res.data.user.image);
            })
            .catch((err) => {
              console.error(err);
            });
        };
  • ์ด๋ฏธ์ง€๋ฆฌ์‚ฌ์ด์ง•์„ ํ†ตํ•œ 10MB ์ด์ƒ์˜ ํ”„๋กœํ•„ ์ด๋ฏธ์ง€๋„ ์—…๋กœ๋“œ ๊ฐ€๋Šฅ (ํ”„๋กœํ•„ ์„ธํŒ…๊ณผ ๋™์ผ)

  • ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ

    • ์ •๊ทœํ‘œํ˜„์‹์„ ํ†ตํ•œ ๊ณ„์ • ID ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ

      // ์˜๋ฌธ, ์ˆซ์ž, ํŠน์ˆ˜๋ฌธ์ž(.), (_)๋งŒ ์‚ฌ์šฉ ๊ฐ€๋Šฅ
      const regex = /*^*[a-z0-9A-Z_.]{0,}*$*/;
    • API ๋ช…์„ธ์— ๋”ฐ๋ฅธ ๊ณ„์ • ID ์ค‘๋ณต ๊ฒ€์‚ฌ

      • defaultAcconutName์„ ๋‘์–ด ๊ธฐ์กด ID ์œ ์ง€ ์‹œ ์ค‘๋ณต ๊ฒ€์‚ฌ X
  • ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ๋ฅผ ํ†ตํ•œ ์ €์žฅ ๋ฒ„ํŠผ ํ™œ์„ฑํ™” (ํ”„๋กœํ•„ ์„ธํŒ…๊ณผ ๋™์ผ)

์ƒํ’ˆ ๊ด€๋ จ ๊ธฐ๋Šฅ
  • ์ƒํ’ˆ ๋“ฑ๋ก

    • ์ด๋ฏธ์ง€๋ฆฌ์‚ฌ์ด์ง•์„ ํ†ตํ•œ 10MB ์ด์ƒ์˜ ์ƒํ’ˆ ์ด๋ฏธ์ง€๋„ ์—…๋กœ๋“œ ๊ฐ€๋Šฅ (ํ”„๋กœํ•„ ์„ค์ •๊ณผ ๋™์ผ)

    • ๊ฐ ์ƒํ’ˆ ์ •๋ณด์˜ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ

      • ์ƒํ’ˆ ์ด๋ฏธ์ง€ (ํ•„์ˆ˜)

      • ์ƒํ’ˆ๋ช… (2~15์ž ์ด๋‚ด)

      • ๊ฐ€๊ฒฉ (์ˆซ์ž๋งŒ ์ž…๋ ฅ ๊ฐ€๋Šฅ)

      • ํŒ๋งค๋งํฌ

        const linkFunction = (value) => {
          const urlRegex = /(http(s)?:\/\/)([a-z0-9\w]+\.*)+[a-z0-9]{2,4}/gi;
          if (urlRegex.test(value)) {
            setLink(value);
          } else {
            setLink('');
          }
        };
    • ์ƒํ’ˆ ๊ฐ€๊ฒฉ์˜ ์ฒœ ๋‹จ์œ„ ์ฝค๋งˆ ์ž๋™ ์ƒ์„ฑ & ์‚ญ์ œ

      // ์ฝค๋งˆ ์ฐ๊ธฐ, ์ฝค๋งˆ ์—†์• ๊ธฐ
      const commaFunction = (value) => {
        const comma = (value) => {
          value = String(value);
          return value.replace(/(\d)(?=(?:\d{3})+(?!\d))/g, '$1,');
        };
        const uncomma = (value) => {
          value = String(value);
          return value.replace(/[^\d]+/g, '');
        };
        return comma(uncomma(value));
      };
  • ์‚ญ์ œ

    • ์ƒํ’ˆ ์‚ญ์ œ ํด๋ฆญ ์‹œ ์ƒํ’ˆ์ด ์‚ญ์ œ ๋˜๊ณ , ํŒ๋งค ์ค‘์ธ ์ƒํ’ˆ๋งŒ ๋ฆฌ๋ Œ๋”๋ง

      const deleteProduct = () => {
        const option = {
          url: `https://mandarin.api.weniv.co.kr/product/${productid}`,
          method: 'DELETE',
          headers: {
            Authorization: `Bearer ${userToken}`,
            'Content-type': 'application/json',
          },
        };
      
        axios(option)
          .then(() => {
            updateProductList(); // ์ƒํ’ˆ ๋ฆฌ์ŠคํŠธ ๋ฆฌ๋ Œ๋”๋ง
          })
          .catch((err) => {
            console.error(err);
          });
      
        closeModal();
      };
      // getProduct()๋กœ ์ƒํ’ˆ ์ •๋ณด๋ฅผ ๋ถˆ๋Ÿฌ์˜ด
      const updateProductList = () => {
          getProduct();
      };
  • ์ˆ˜์ •

    • ๊ธฐ์กด ์ƒํ’ˆ ์ •๋ณด ๋ถˆ๋Ÿฌ์˜ค๊ธฐ (์ƒํ’ˆ ์ด๋ฏธ์ง€ ๋ฏธ๋ฆฌ๋ณด๊ธฐ ํฌํ•จ)
    • ์ƒํ’ˆ ๋“ฑ๋ก๊ณผ ๋™์ผํ•œ ๊ธฐ๋Šฅ ํฌํ•จ
    const params = useParams();
    ...
    const onClickProductModificationHandler = () => {
      const option = {
        url: `https://mandarin.api.weniv.co.kr/product/${params.productid}`,
        method: 'PUT',
        headers: {
          Authorization: `Bearer ${userToken}`,
          'Content-type': 'application/json',
        },
        data: {
          product: {
            itemName: itemNameMod,
            price: priceMod,
            link: linkMod,
            itemImage: itemImageMod,
          },
        },
      };
    
      axios(option)
        .then((res) => {
          console.log(res);
        })
        .catch((err) => {
          console.error(err);
        });
    };
    ...
  • ์›น์‚ฌ์ดํŠธ์—์„œ ์ƒํ’ˆ ๋ณด๊ธฐ

    • ๋‚ด ์ƒํ’ˆ์— ๋Œ€ํ•ด ์›น์‚ฌ์ดํŠธ์—์„œ ์ƒํ’ˆ ๋ณด๊ธฐ ํด๋ฆญ ์‹œ, ํ•ด๋‹น ํŽ˜์ด์ง€๊ฐ€ ์ƒˆ ์ฐฝ์œผ๋กœ ์—ด๋ฆผ

      <a rel='noopener noreferrer' target='_blank' href={productLink}>์›น์‚ฌ์ดํŠธ์—์„œ ์ƒํ’ˆ ๋ณด๊ธฐ</a>

๐Ÿฃ ๋ฐฐ์Šน์—ฐ

React Router 6๋ฅผ ์ด์šฉํ•ด ์ธ์ฆ(๋กœ๊ทธ์ธ) ์—ฌ๋ถ€์— ๋”ฐ๋ฅธ ์ ‘๊ทผ ์ œํ•œ ๊ตฌํ˜„

์ธ์ฆ ์—ฌ๋ถ€์— ๋”ฐ๋ฅธ ์ ‘๊ทผ ์ œํ•œ ์ธก๋ฉด์—์„œ ๋ดค์„ ๋•Œ ์„ธ ์ข…๋ฅ˜์˜ ํŽ˜์ด์ง€๊ฐ€ ์กด์žฌ

  • ์ธ์ฆ ์—ฌ๋ถ€์— ์ƒ๊ด€ ์—†์ด ์ ‘๊ทผ ๊ฐ€๋Šฅํ•œ ํŽ˜์ด์ง€
  • ์ธ์ฆ ์•ˆ ๋œ ๊ฒฝ์šฐ๋งŒ ์ ‘๊ทผ ๊ฐ€๋Šฅํ•œ ํŽ˜์ด์ง€
  • ์ธ์ฆ ๋œ ๊ฒฝ์šฐ๋งŒ ์ ‘๊ทผ ๊ฐ€๋Šฅํ•œ ํŽ˜์ด์ง€

์ธ์ฆ ๋œ ๊ฒฝ์šฐ๋งŒ ์ ‘๊ทผ ๊ฐ€๋Šฅํ•œ ๊ฒฝ์šฐ / ์•ˆ ๋œ ๊ฒฝ์šฐ๋งŒ ์ ‘๊ทผ ๊ฐ€๋Šฅํ•œ ๊ฒฝ์šฐ, ๋‘ ์ผ€์ด์Šค์— ๋Œ€ํ•œ ์ ‘๊ทผ ์ œํ•œ์„ ๊ตฌํ˜„ํ•˜๊ธฐ ์œ„ํ•ด ์ค‘์ฒฉ ๋ผ์šฐํŒ… ์‚ฌ์šฉ

/* Router.jsx ์ผ๋ถ€ */

import { AuthContextStore } from '../context/AuthContext';

const Router = () => {
  const { userToken } = useContext(AuthContextStore);

  return (
    <Routes>
      <Route path='*' element={<Error404Page />} />
      <Route path='/notfound' element={<Error404Page />} />

      <Route element={<NonAuthRoute authenticated={userToken} />}>
        <Route path='/' element={<SplashScreen />} />
        <Route path='/login' element={<EmailLoginPage />} />
        ...
      </Route>

      <Route element={<AuthRoute authenticated={userToken} />}>
        <Route path='/home' element={<FeedPage />} />
        <Route path='/search' element={<SearchPage />} />
        ...
      </Route>
    </Routes>
  );
};

์•„๋ž˜ ์˜ˆ์‹œ๋Š” ์ธ์ฆ ๋œ ๊ฒฝ์šฐ๋งŒ ์ ‘๊ทผ ๊ฐ€๋Šฅํ•œ ํŽ˜์ด์ง€๋ฅผ ๊ฐ์‹ธ๊ณ  ์žˆ๋Š” AuthRoute ์ปดํฌ๋„ŒํŠธ ์ƒ์„ธ ์ฝ”๋“œ

/* AuthRoute.jsx */

import React from 'react';
import { Navigate, Outlet } from 'react-router-dom';

const AuthRoute = ({ authenticated, redirectPath = '/' }) => {
  if (!authenticated) {
    return <Navigate to={redirectPath} />;
  }

  return <Outlet />;
};

export default AuthRoute;
  • ์ „๋‹ฌ ๋ฐ›๋Š” ๋ฐ์ดํ„ฐ ์„ค๋ช…
    • authenticated : Context์— ์ €์žฅ๋œ ์‚ฌ์šฉ์ž token ๋ฐ์ดํ„ฐ
    • redirectPath : ์ธ์ฆ์ด ์•ˆ ๋œ ๊ฒฝ์šฐ ๋ฆฌ๋‹ค์ด๋ ‰ํŠธ ๋  ๊ฒฝ๋กœ(/)๋ฅผ ๊ธฐ๋ณธ๊ฐ’์œผ๋กœ ๊ฐ–๊ณ  ์žˆ์Œ
  • ๋™์ž‘ ์„ค๋ช…
    • ์ •์ƒ์ ์œผ๋กœ ์ธ์ฆ์ด ๋˜์ง€ ์•Š์€ ๊ฒฝ์šฐ(์‚ฌ์šฉ์ž token์ด Falsy ๊ฐ’์„ ๊ฐ–๋Š” ๊ฒฝ์šฐ) / ๊ฒฝ๋กœ๋กœ ๋ฆฌ๋‹ค์ด๋ ‰ํŠธ ๋จ
    • ์ •์ƒ์ ์œผ๋กœ ์ธ์ฆ์ด ๋œ ๊ฒฝ์šฐ Outlet ์†์„ฑ์„ ์ด์šฉํ•ด ์‚ฌ์šฉ์ž๊ฐ€ ์ ‘๊ทผํ•˜๋ ค๋Š” ํŽ˜์ด์ง€๊ฐ€ ๋ Œ๋”๋ง ๋จ

์‹ค์‹œ๊ฐ„ ๋‚ ์”จ๋ฅผ ๋ฐ”ํƒ•์œผ๋กœ ๊ฐ•์•„์ง€ ์‚ฐ์ฑ… ๋‚œ์ด๋„ ๊ณ„์‚ฐ

1. ์—ฌ๋Ÿฌ ๊ฐœ์˜ API ์š”์ฒญ๊ณผ ์‘๋‹ต์„ ํ•œ ๋ฒˆ์— ์ฒ˜๋ฆฌํ•˜๊ธฐ ์œ„ํ•œ Axios multiple request ์‚ฌ์šฉ

  • ์‚ฐ์ฑ… ๋‚œ์ด๋„(๋‚ ์”จ) ํŽ˜์ด์ง€ ๊ตฌํ˜„ ์‹œ ๋‚ ์”จ API์™€ ๋ฏธ์„ธ๋จผ์ง€ API์— ๊ฐ๊ฐ ์š”์ฒญ์„ ๋ณด๋‚ด๊ณ , ์‘๋‹ต์„ ์ฒ˜๋ฆฌํ•˜๋Š” ๊ณผ์ •์ด ํ•„์š”ํ–ˆ์Œ

  • ์ด๋•Œ Axios์˜ multiple request ๊ธฐ๋Šฅ์„ ์ด์šฉํ•ด์„œ ๋™์‹œ์— ๋‹ค์ค‘ ์š”์ฒญ์„ ๋ณด๋‚ด๋„๋ก ์ฒ˜๋ฆฌํ•จ

    /* CommunityWeatherPage.jsx ์ผ๋ถ€ */
    
    const CommunityWeatherPage = () => {
      const { longitude, latitude, error } = useContext(UserLocationContextStore);
      const OPEN_WEATHER_MAP_API = process.env.REACT_APP_OPEN_WEATHER_MAP_API;
    
      useEffect(() => {
        const getFetch = async () => {
          await axios
            .all([
              axios.get(
                `https://api.openweathermap.org/data/2.5/weather
                  ?lat=${latitude}&lon=${longitude}&appid=${OPEN_WEATHER_MAP_API}&units=metric`,
              ),
              axios.get(
                `https://api.openweathermap.org/data/2.5/air_pollution
                  ?lat=${latitude}&lon=${longitude}&appid=${OPEN_WEATHER_MAP_API}`,
              ),
            ])
            .then(
              axios.spread((weatherRes, dustRes) => {
                updateWeatherInfo(weatherRes);
                updateDustInfo(dustRes);
              }),
            );
        };
    
      getFetch();
    }, [longitude, latitude]);
    • axios.all()์„ ์ด์šฉํ•ด์„œ ์—ฌ๋Ÿฌ ๊ฐœ์˜ ์š”์ฒญ์„ ๋ฌถ์–ด์„œ ํ•œ ๋ฒˆ์— ๋ณด๋‚ด๋„๋ก ํ•จ. ์œ„ ์˜ˆ์‹œ์—์„œ๋Š” 2๊ฐœ์˜ ์š”์ฒญ๋งŒ ํ•œ ๋ฒˆ์— ์ฒ˜๋ฆฌํ•˜๊ณ  ์žˆ์œผ๋‚˜ 3๊ฐœ ์ด์ƒ๋„ ๊ฐ€๋Šฅ
    • axios.spread()๋ฅผ ์ด์šฉํ•ด์„œ ์š”์ฒญ์— ๋Œ€ํ•œ ์‘๋‹ต์„ ๊ฐ๊ฐ ๋ฐ›์•„์˜ค๋„๋ก ํ•จ

2. ๋‚ ์”จ ์ถœ๋ ฅ ๋ฐ ๋‚ ์”จ ์ ์ˆ˜ ๊ณ„์‚ฐ์„ ์œ„ํ•œ WeatherDescription ๊ฐ์ฒด ์ƒ์„ฑ

  • WeatherDescription ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•œ ์ด์œ 

    • ์‚ฌ์šฉํ•œ ๋‚ ์”จ API(OpenWeatherMap)์˜ ๊ฒฝ์šฐ ํ•ด์™ธ์—์„œ ์ œ๊ณตํ•˜๋Š” API๋ผ ๋‚ด๋ถ€์ ์œผ๋กœ ์ œ๊ณตํ•˜๊ณ  ์žˆ๋Š” ๋ฒˆ์—ญ ๊ธฐ๋Šฅ์˜ ์„ฑ๋Šฅ์ด ๋ฏธํกํ•˜์˜€์Œ
    • ๋˜ํ•œ ์‚ฐ์ฑ… ๋‚œ์ด๋„ ๊ณ„์‚ฐ ์‹œ ๋‚ ์”จ ์ ์ˆ˜๋ฅผ ์ฑ…์ •ํ•  ํ•„์š”๊ฐ€ ์žˆ์—ˆ์Œ

    /* WeatherDescription.jsx ์ผ๋ถ€ */
    
    const WeatherDescription = {
      202: { title: 'ํญ์šฐ๋ฅผ ๋™๋ฐ˜ํ•œ ์ฒœ๋‘ฅ๊ตฌ๋ฆ„', score: 10 },
      210: { title: '์•ฝํ•œ ์ฒœ๋‘ฅ๊ตฌ๋ฆ„', score: 2 },
      211: { title: '์ฒœ๋‘ฅ๊ตฌ๋ฆ„', score: 2 },
      212: { title: '๊ฐ•ํ•œ ์ฒœ๋‘ฅ๊ตฌ๋ฆ„', score: 10 },
      221: { title: '๋ถˆ๊ทœ์น™์  ์ฒœ๋‘ฅ๊ตฌ๋ฆ„', score: 2 },
      230: { title: '์•ฝํ•œ ์Šค๋ชจ๊ทธ๋ฅผ ๋™๋ฐ˜ํ•œ ์ฒœ๋‘ฅ๊ตฌ๋ฆ„', score: 2 },
      ...
    };
    • WeatherDescription ๊ฐ์ฒด ์„ค๋ช…
      • ๋‚ ์”จ API์˜ ์‘๋‹ต์œผ๋กœ ์˜ค๋Š” ๋‚ ์”จ id๋ฅผ ๊ฐ์ฒด์˜ key๋กœ ์‚ฌ์šฉํ•จ
      • value๋กœ title(ํ•œ๊ตญ์–ด๋กœ ๋ฒˆ์—ญํ•œ ๋‚ ์”จ)์™€ score(๋‚ ์”จ ์ ์ˆ˜)๋ฅผ ๊ฐ€์ง

  • ์•„๋ž˜ ์˜ˆ์‹œ๋Š” ์‹ค์ œ ์‚ฌ์šฉ ์˜ˆ์‹œ

    /* CommunityWeatherPage.jsx ์ผ๋ถ€ */
    
    import WeatherDescription from '../../../utils/WeatherDescription';
    
    const CommunityWeatherPage = () => {
      const { longitude, latitude, error } = useContext(UserLocationContextStore);
      const [weatherInfo, setWeatherInfo] = useState({});
    
      useEffect(() => {
        const updateWeatherInfo = (res) => {
          const weatherData = res.data;
    
          setWeatherInfo({
            weather: WeatherDescription[weatherData.weather[0].id].title,
            weatherScore: WeatherDescription[weatherData.weather[0].id].score,
            ...
          });
        };
    
        getFetch();
      }, [longitude, latitude]);
    }
    • weatherData.weather[0].id : ๋‚ ์”จ API์˜ ์‘๋‹ต์œผ๋กœ ์˜ค๋Š” ๋‚ ์”จ id

3. ์‚ฐ์ฑ… ๋‚œ์ด๋„ ๊ณ„์‚ฐ ๊ธฐ์ค€

* ์‚ฐ์ฑ… ๋‚œ์ด๋„ ๊ทธ๋ฃน : ๊ธฐ์˜จ / ๋‚ ์”จ / ๊ณต๊ธฐ ์งˆ
* ๊ฐ ๊ทธ๋ฃน์˜ ์ƒํƒœ๋Š” ์ตœ์ƒ / ์ƒ / ์ค‘ / ํ•˜๋กœ ํ‰๊ฐ€ํ•œ๋‹ค.
* ์ตœ์ƒ / ์ƒ์€ ์‚ฐ์ฑ… ์–ด๋ ค์›€, ์ค‘์€ ๋ณดํ†ต, ํ•˜๋Š” ์‚ฐ์ฑ… ์‰ฌ์›€์ด๋‹ค.
* ์ตœ์ƒ์€ 10์ , ์ƒ์€ 2์ , ์ค‘์€ 1์ , ํ•˜๋Š” 0์ ์˜ ์ ์ˆ˜๋ฅผ ๊ฐ–๋Š”๋‹ค.
* ์ตœ์ƒ์ด ํ•˜๋‚˜๋ผ๋„ ๊ปด์žˆ์œผ๋ฉด ์‚ฐ์ฑ… ์–ด๋ ค์›€์œผ๋กœ ์ฑ…์ •๋œ๋‹ค.

* ๊ธฐ์˜จ
์†Œํ˜•๊ฒฌ์„ ๊ธฐ์ค€์œผ๋กœ ํ•จ
๊ธฐ์˜จ ์ƒ, ์ค‘, ํ•˜๋ฅผ ๋‚˜๋ˆŒ๋•Œ๋Š” TACC ์Šค์ผ€์ผ์„ ์ฐธ๊ณ 
  > ๊ฒจ์šธ ๋‚ ์”จ ์ฐธ๊ณ  : https://www.k-health.com/news/articleView.html?idxno=57536
  > ์—ฌ๋ฆ„ ๋‚ ์”จ ์ฐธ๊ณ  : https://purplejam.kr/hot-summer-dog/
- ์ตœ์ƒ : -9๋„ ์•„๋ž˜, 35๋„ ์œ„ (+10)
- ์ƒ : -8๋„ ~ -2๋„, 27๋„ ~ 34๋„ (+2)
- ์ค‘ : -1๋„ ~ 6๋„, 23๋„ ~ 26๋„ (+1)
- ํ•˜ : 7๋„ ~ 22๋„ (0)

* ๋‚ ์”จ
OpenWeatherMap API๊ฐ€ ์‘๋‹ตํ•ด์ฃผ๋Š” ๊ฐ’ ์ค‘ ๋‚ ์”จ ์•„์ด๋”” ๊ฐ’์ธ weather.id๋กœ ํŒ๋‹จ
๋‚ ์”จ์— ๋”ฐ๋ฅธ ์ ์ˆ˜ ๋ถ€์—ฌ
  > utils/WeatherDescription.jsx์— scroe ์ถ”๊ฐ€
- ์ตœ์ƒ : ํญ์„ค, ํญ์šฐ, ํƒœํ’, ๊ณ ์˜จ, ํ•œ๋žญ, ๋Œํ’, ์šฐ๋ฐ•, ์Šค๋ชจ๊ทธ, ํ™ฉ์‚ฌ ๋“ฑ (+10)
- ์ƒ : ๊ฐ•ํ•œ ๋น„, ์„ผ ๋ฐ”๋žŒ, ์ฒœ๋‘ฅ ๊ตฌ๋ฆ„ ๋“ฑ (+2)
- ์ค‘ : ์ ์€~์ค‘๊ฐ„ ๋น„, ์ ์€~์ค‘๊ฐ„ ๋ˆˆ, ์•ฝํ•œ~์ค‘๊ฐ„ ์„ธ๊ธฐ ๋ฐ”๋žŒ, ์•ˆ๊ฐœ ๋“ฑ (+1)
- ํ•˜ : ๋ฐ”๋žŒ ๊ฑฐ์˜ ์—†์Œ, ๋ง‘์€ ํ•˜๋Š˜, ์–‡๊ฒŒ ๋‚€ ์•ˆ๊ฐœ ๋“ฑ (0)

* ๋Œ€๊ธฐ ์งˆ
OpenWeatherMap API๊ฐ€ ์‘๋‹ตํ•ด์ฃผ๋Š” ๊ฐ’ ์ค‘ aqi ๊ฐ’์œผ๋กœ ํŒ๋‹จ
aqi ๊ฐ’์€ ๋Œ€๊ธฐ ์งˆ์„ 1~5๋กœ ํ‰๊ฐ€ํ•œ ๊ฐ’์ž„
  > API ๋งํฌ : https://openweathermap.org/api/air-pollution
- ์ตœ์ƒ : 5 (+10)
- ์ƒ : 4 (+2)
- ์ค‘ : 2~3 (+1)
- ํ•˜ : 1 (0)

* ์‚ฐ์ฑ… ๋‚œ์ด๋„๋ฅผ ๊ตฌํ•˜๊ธฐ ์œ„ํ•ด ์„ธ ๊ทธ๋ฃน์˜ ์ ์ˆ˜๋ฅผ ๋”ํ•œ๋‹ค.
* ๋‚œ์ด๋„ ์ฑ…์ • ๊ธฐ์ค€
- ์–ด๋ ค์›€ : 5 ์ด์ƒ (์ตœ์ƒ์ด ํ•˜๋‚˜๋ผ๋„ ๊ปด์žˆ์œผ๋ฉด ์‚ฐ์ฑ… ์–ด๋ ค์›€์œผ๋กœ ์ฑ…์ •๋จ)
- ๋ณดํ†ต : 2, 3, 4
- ์‰ฌ์›€ : 0, 1

4. ์‚ฐ์ฑ… ๋‚œ์ด๋„ ํŽ˜์ด์ง€ ๋‚ด ์‚ฌ์šฉ์ž ๊ฒฝํ—˜์„ ํ–ฅ์ƒํ•˜๊ธฐ ์œ„ํ•œ ์‹œ๋„


์„œ๋ฒ„ ๊ฐœ๋ฐœ์ž์™€ ์†Œํ†ต์ด ์–ด๋ ค์šด ์˜คํ”ˆ API์˜ ํ•œ๊ณ„๋ฅผ ๊ทน๋ณตํ•˜๊ธฐ ์œ„ํ•œ ๋™๋ฌผ๋ณ‘์› ์ƒ์„ธ๋ณด๊ธฐ ํŽ˜์ด์ง€ URL ๊ตฌ์„ฑ

๋™๋ฌผ๋ณ‘์› ์ƒ์„ธ๋ณด๊ธฐ ํŽ˜์ด์ง€์—์„œ ์žฅ์†Œ ์ •๋ณด๋ฅผ ์–ด๋–ป๊ฒŒ ๊ฐ€์ ธ์˜ฌ๊ฒƒ์ธ์ง€์— ๋Œ€ํ•œ ๊ณ ๋ฏผ์ด ์ƒ๊น€

  • ์žฅ์†Œ id๋ฅผ ์ด์šฉํ•ด ํ•ด๋‹น ์žฅ์†Œ์— ๋Œ€ํ•œ ์ƒ์„ธ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ค๋ ค๊ณ  ํ–ˆ์œผ๋‚˜, ํ™•์ธ ๊ฒฐ๊ณผ ์นด์นด์˜ค๋งต API๋Š” ๊ทธ๋Ÿฌํ•œ ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•˜์ง€ ์•Š๊ณ  ์žˆ์—ˆ์Œ
  • ๋”ฐ๋ผ์„œ URL์— ์žฅ์†Œ์— ๋Œ€ํ•œ ์ƒ์„ธ ์ •๋ณด๋ฅผ ๋‹ด์•„ ๋ณด๋‚ด๊ธฐ๋กœ ํ•จ

์žฅ์†Œ์— ๋Œ€ํ•œ ์ƒ์„ธ ์ •๋ณด๋ฅผ ๋‹ด๊ณ  ์žˆ๋Š” URL ์ƒ์„ฑ

/* HospitalItem.jsx ์ผ๋ถ€ */

const HospitalItem = ({ hospitalInfo }) => {
  const [detailUrl, setDetailUrl] = useState(null);

  useEffect(() => {
    if (Object.keys(hospitalInfo).length > 0) {
      const url =
        '?road_address=' +
        hospitalInfo.road_address_name +
        '&place_name=' +
        hospitalInfo.place_name +
        '&phone=' +
        hospitalInfo.phone +
        '&x=' +
        hospitalInfo.x +
        '&y=' +
        hospitalInfo.y;

      const encodeResult = encodeURI('/community/hospital' + url);
      setDetailUrl(encodeResult);
    }
  }, [hospitalInfo]);

  return (
    <HospitalItemWrapper>
      <HospitalLink to={detailUrl} aria-label={`${hospitalInfo.place_name} ์ƒ์„ธ ์ •๋ณด`}>
        ...
      </HospitalLink>
    </HospitalItemWrapper>
  );
};
  • ๋„๋กœ๋ช… ์ฃผ์†Œ, ์žฅ์†Œ๋ช…, ์ „ํ™”๋ฒˆํ˜ธ, x์ขŒํ‘œ, y์ขŒํ‘œ๋ฅผ URL์— ํฌํ•จํ•จ
  • ์ด๋•Œ ์‹ค์ œ๋กœ๋Š” ๋‹จ์ˆœํžˆ URL์— ์žˆ๋Š” ์ •๋ณด๋ฅผ ๊บผ๋‚ด์™€์„œ ์ƒ์„ธ๋ณด๊ธฐ ํŽ˜์ด์ง€๋ฅผ ๊ตฌํ˜„ํ•  ์˜ˆ์ •์ด์—ˆ์œผ๋‚˜, ๋ณดํŽธ์ ์ธ ํ˜•ํƒœ์˜ URL๋กœ ๊ตฌ์„ฑํ•˜๊ธฐ ์œ„ํ•ด ์„œ๋ฒ„์— ๋ฐ์ดํ„ฐ๋ฅผ ์ „์†กํ•˜๋Š” ๊ฒƒ๊ณผ ๊ฐ™์€ ํ˜•ํƒœ(์ฟผ๋ฆฌ์ŠคํŠธ๋ง)๋กœ URL์„ ๊ตฌ์„ฑ
  • encodeURI()๋ฅผ ์ด์šฉํ•ด์„œ ์˜ˆ์•ฝ๋œ ๋ฌธ์ž๋ฅผ ์ œ์™ธํ•œ ๋ฌธ์ž๋ฅผ ์ธ์ฝ”๋”ฉ ์ฒ˜๋ฆฌ
    • ๋ฆฌ์ŠคํŠธ ์•„์ดํ…œ UI

    • ๋ฆฌ์ŠคํŠธ ์•„์ดํ…œ ๊ฐœ๋ฐœ์ž๋„๊ตฌ ํ™•์ธ ์‹œ ์ธ์ฝ”๋”ฉ๋œ URI ํ™•์ธ ๊ฐ€๋Šฅ

    • ์‹ค์ œ ์ฃผ์†Œ์ฐฝ์—๋Š” ๋””์ฝ”๋”ฉ๋œ ํ˜•ํƒœ๋กœ ํ‘œ์‹œ๋˜์–ด ํ™•์ธ ๊ฒฐ๊ณผ React Router ์‚ฌ์šฉ์‹œ ์ž๋™ ๋””์ฝ”๋”ฉ๋จ


URL์— ๋‹ด๊ฒจ์žˆ๋Š” ์ •๋ณด๋ฅผ ์ด์šฉํ•ด ํ™”๋ฉด์— ํ‘œ์‹œํ•˜๊ธฐ

/* CommunityHospitalDetailPage.jsx ์ผ๋ถ€ */

const CommunityHospitalDetailPage = () => {
  const [searchParams, setSearchParams] = useSearchParams();
  const [hospitalInfo, setHospitalInfo] = useState({});

  useEffect(() => {
    setHospitalInfo({
      address: searchParams.get('road_address'),
      name: searchParams.get('place_name'),
      phone: searchParams.get('phone'),
      x: searchParams.get('x'),
      y: searchParams.get('y'),
    });
  }, []);

  return (
          <CommunityLayout padding='0' navType='titleNav' currentMenuId={2}
            isViewTabMenu={false} fillHeight={true} title={hospitalInfo.name}>
              <HospitalDetailWrapper>
              ...
              <HospitalDetail hospitalInfo={hospitalInfo} />
            </HospitalDetailWrapper>
          </CommunityLayout>
    );
}
  • useSearchParams() ํ›…์„ ์ด์šฉํ•ด์„œ ์ฟผ๋ฆฌ์ŠคํŠธ๋ง์„ ๋‹ค๋ฃธ
    • searchParams.get(key) ๋ฉ”์„œ๋“œ๋ฅผ ์ด์šฉํ•ด์„œ ํ•ด๋‹น key์˜ value๋ฅผ ๊ฐ€์ ธ์˜ด
  • ๊ฐ€์ ธ์˜จ ๋ฐ์ดํ„ฐ๋ฅผ hospitalInfo ๊ฐ์ฒด์— ์ €์žฅํ•œ ํ›„ ํ™”๋ฉด์— ํ‘œ์‹œ

์ด๋ฏธ์ง€ ๋ฐ์ดํ„ฐ ๋ณ€๊ฒฝ์— ์œ ์—ฐํ•œ ํŽ˜์ด์ง€๋„ค์ด์…˜ ์บ๋Ÿฌ์…€ ์ปดํฌ๋„ŒํŠธ
/* PaginationCarousle.jsx ์ผ๋ถ€ */

const PaginationCarousel = ({ itemList }) => {
  return (
    <>
      <Swiper
        modules={[Autoplay, Pagination]}
        pagination={{
          dynamicBullets: true,
        }}
        loop='true'
        autoplay={{ delay: 2500, disableOnInteraction: false }}
      >
        {itemList.map(({ id, src, alt }) => (
          <SwiperSlide key={id}>
            <img src={src} alt={alt} />
          </SwiperSlide>
        ))}
      </Swiper>
    </>
  );
};
  • ์‰ฝ๊ฒŒ ํ™•์žฅํ•  ์ˆ˜ ์žˆ๋„๋ก ๊ฐ์ฒด ๋ฐฐ์—ด ํ˜•ํƒœ์ธ itemList๋ฅผ props๋กœ ์ „๋‹ฌ๋ฐ›๋„๋ก ํ•จ. ์ „๋‹ฌ๋ฐ›์€ itemList๋Š” ๋ฐ˜๋ณต์„ ๋Œ๋ฉฐ ์บ๋Ÿฌ์…€ ์•„์ดํ…œ(SwiperSlide)์œผ๋กœ ์ถ”๊ฐ€๋จ
  • ์บ๋Ÿฌ์…€ ๊ตฌํ˜„์€ Swiper ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์ด์šฉ

์‹ค์ œ ์‚ฌ์šฉ ์˜ˆ

/* CommunityMainPage ์ผ๋ถ€ */

import { ADVERTISING1_IMAGE, ADVERTISING2_IMAGE,
   ADVERTISING3_IMAGE, ADVERTISING4_IMAGE } from './../../../styles/CommonImages';

const CommunityMainPage = () => {
  const advertisingImageList = [
    { id: 0, src: ADVERTISING1_IMAGE, alt: '์‚ฐ์ฑ… ๋‚œ์ด๋„ ์„œ๋น„์Šค ์˜คํ”ˆ! ์‹ค์‹œ๊ฐ„ ๋‚ ์”จ ํ™•์ธํ•˜๊ณ  ๋Œ•๋Œ•์ด๋ž‘ ์‚ฐ์ฑ…๊ฐ€์ž!' },
    { id: 1, src: ADVERTISING2_IMAGE, alt: '์ง‘์‚ฌ์ƒํ™œ ํŽ˜์ด์ง€ ๋Ÿฐ์นญ! ์šฐ๋ฆฌ์ง‘ ๋Œ•๋ƒฅ์ด๋ฅผ ์œ„ํ•œ ํ›Œ๋ฅญํ•œ ์ง‘์‚ฌ ๋˜๊ธฐ' },
    { id: 2, src: ADVERTISING3_IMAGE, alt: 'ํŠน๋ณ„ ์ด๋ฒคํŠธ! ์นœ๊ตฌ ์ดˆ๋Œ€ํ•˜๊ณ  ์• ๊ฒฌํ˜ธํ…” ๋ฌด๋ฃŒ๋กœ ๊ฐ€๊ธฐ' },
    { id: 3, src: ADVERTISING4_IMAGE, alt: 'ํ˜„์žฌ ์œ„์น˜์—์„œ ๊ฐ€์žฅ ๊ฐ€๊นŒ์šด ๋™๋ฌผ๋ณ‘์› ์ฐพ๊ธฐ ์„œ๋น„์Šค ์˜คํ”ˆ!' },
  ];

  return (
    <CommunityLayout currentMenuId={0} fillHeight={isEmpty}>
      <PaginationCarousel itemList={advertisingImageList} />
      <PopularPosts isEmpty={isEmpty} changeEmptyState={changeEmptyState} />
    </CommunityLayout>
  );
};
  • id, src, alt ๊ฐ’์„ ๊ฐ–๋Š” ์žˆ๋Š” ๊ฐ์ฒด ๋ฐฐ์—ด์„ ๋งŒ๋“  ํ›„ PaginationCrousel ์ปดํฌ๋„ŒํŠธ์— ์ „๋‹ฌํ•˜๋ฉด ํŽ˜์ด์ง€๋„ค์ด์…˜ ์บ๋Ÿฌ์…€์ด ํ™”๋ฉด์— ์ถœ๋ ฅ๋จ
  • ๋งŒ์•ฝ ์ด๋ฏธ์ง€๋ฅผ ์ถ”๊ฐ€ํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด ๊ฐ์ฒด ๋ฐฐ์—ด ์•ˆ ๋ฐ์ดํ„ฐ๋ฅผ ์ถ”๊ฐ€ํ•˜๋ฉด ๊ฐ„๋‹จํ•˜๊ฒŒ ์บ๋Ÿฌ์…€ ์ด๋ฏธ์ง€ ์ถ”๊ฐ€ ๊ฐ€๋Šฅ

๐ŸŒธ ์ด๊ด‘๋ ฌ

ํšŒ์›๊ฐ€์ž… ๊ธฐ๋Šฅ ๊ตฌํ˜„ (email, password)
  • email ๊ณผ password ์˜ input ์ฐฝ์— text ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ›์•„์„œ, ๊ฐ๊ฐ์˜ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ ํ…Œ์ŠคํŠธํ•˜์—ฌ ํ†ต๊ณผํ•˜๋ฉด ํด๋ฆญ ์ด๋ฒคํŠธ๋ฅผ ํ†ตํ•˜์—ฌ, useNavigate() ๋ฅผ ํ™œ์šฉํ•ด ํ•ด๋‹น ํŽ˜์ด์ง€์— state ์ •๋ณด๋ฅผ ๋„˜๊ธด๋‹ค.

    ...
    navigate('/join/setprofile', {
      state: {
        email: email,
        password: password,
      },
    });
    ...

๊ฒ€์ƒ‰ ๊ธฐ๋Šฅ ๊ตฌํ˜„
  1. input ์ฐฝ์— ๊ฒ€์ƒ‰ํ•œ ํ‚ค์›Œ๋“œ์™€ ๋™์ผํ•œ ์ •๋ณด ( ์‚ฌ์šฉ์ž ID ์™€ ์‚ฌ์šฉ์ž ์ด๋ฆ„ ) ๋ฅผ GET ์š”์ฒญ์„ ํ†ตํ•˜์—ฌ ๋ฐ›์•„์˜ด
  2. ์‚ฌ์šฉ์ž ID๊ฐ€ ์•„๋‹Œ, ์‚ฌ์šฉ์ž ์ด๋ฆ„ ๊ณผ input ์ฐฝ์— ์ž…๋ ฅํ•œ ํ‚ค์›Œ๋“œ๊ฐ€ ๋™์ผํ•œ ๋ถ€๋ถ„์ด ์žˆ๋Š” ๊ฒฝ์šฐ์—๋Š” ์ž…๋ ฅํ•œ ํ‚ค์›Œ๋“œ ๋ถ€๋ถ„๋งŒ ๋‹ค๋ฅธ ์Šคํƒ€์ผ ์ ์šฉํ•˜์—ฌ ๊ฐ•์กฐ
// ํ‚ค์›Œ๋“œ๊ฐ€ ์‚ฌ์šฉ์ž ์ด๋ฆ„ ๊ณผ ๋ถ€๋ถ„์ ์œผ๋กœ ๊ฒน์น˜๋Š”์ง€, ์•„๋‹ˆ๋ฉด ์‚ฌ์šฉ์ž ID ์™€ ๋ถ€๋ถ„์ ์œผ๋กœ ๊ฒน์น˜๋Š”์ง€ ํŒ๋‹จํ•˜๊ธฐ ์œ„ํ•ด์„œ indexOf ์‚ฌ์šฉ
const usernameValidate = ~username.indexOf(keyword);
const accountnameValidate = ~accountname.indexOf(keyword);
// username ์„ ๊ฒ€์ƒ‰ ํ‚ค์›Œ๋“œ๋ฅผ ์ค‘์‹ฌ์œผ๋กœ ์ž˜๋ผ์„œ, 3๊ฐœ์˜ ๋ฌธ์ž์—ด์„ ๋ฐฐ์—ด๋กœ ์ €์žฅ 
const COMMA_APPEND_USERNAME = username.replace(keyword, `,${keyword},`);
const arrayKeyword = COMMA_APPEND_USERNAME.split(',');
<span>
  // ํ‚ค์›Œ๋“œ ๋ถ€๋ถ„๋งŒ ๋”ฐ๋กœ styled-component ๋ฅผ ์ƒ์„ฑํ•˜์—ฌ, ๊ฐ•์กฐ
  {arrayKeyword[0]}
  <Keyword>{arrayKeyword[1]}</Keyword>
  {arrayKeyword[2]}
</span>

๊ฒŒ์‹œ๊ธ€ ๊ด€๋ จ ๊ธฐ๋Šฅ ๊ตฌํ˜„
  • ๊ฒŒ์‹œ๊ธ€ ์กฐํšŒ

    • useParams()๋ฅผ ํ†ตํ•˜์—ฌ, ํ•ด๋‹น ํŽ˜์ด์ง€์˜ ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ๊ฐ€์ ธ์™€, ํ•ด๋‹นํ•˜๋Š” ๊ฒŒ์‹œ๋ฌผ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ›์•„์˜ด
  • ๊ฒŒ์‹œ๊ธ€ ๋“ฑ๋ก

    • ๊ฐ ์ด๋ฒคํŠธ๋“ค๋กœ ํ•˜์—ฌ๊ธˆ ๋ธŒ๋ผ์šฐ์ €์˜ ๊ธฐ๋ณธ ๋™์ž‘์„ ์‹คํ–‰ํ•˜์ง€ ์•Š๋„๋ก preventDefault ๋กœ ๋ง‰์Œ
    • ์ด๋ฏธ์ง€ - ์ด๋ฏธ์ง€๋ฅผ ์—…๋กœ๋“œ ํ•˜๊ธฐ์œ„ํ•ด, ์–‘์‹์— ๋งž๋„๋ก ์ด๋ฏธ์ง€ url ์„ ์ˆ˜์ •ํ•˜๋Š” ์ž‘์—…์„ ๊ฑฐ์ณ์„œ ์„œ๋ฒ„์— ์ „์†ก ์ค€๋น„
    • ๊ฒŒ์‹œ๊ธ€ ํ…์ŠคํŠธ - event.target.value ๋ฅผ ํ†ตํ•˜์—ฌ, ํ…์ŠคํŠธ๋ฅผ ์‹ค์‹œ๊ฐ„ ์ €์žฅํ•˜์—ฌ ์ƒํƒœ๊ด€๋ฆฌ ํ›„ ์„œ๋ฒ„์— ์ „์†ก ์ค€๋น„
      • ๊ฒŒ์‹œ๊ธ€ ๊ธธ์ด์— ๋งž๊ฒŒ, input ์ฐฝ ํฌ๊ธฐ ๋ณ€๊ฒฝ
      // ํ…์ŠคํŠธ์˜ ๊ธธ์ด์— ๋งž์ถ”์–ด ๋ฐ•์Šคํฌ๊ธฐ ์กฐ์ •
      const textRef = useRef();
      const handleResizeHeight = useCallback(() => {
        textRef.current.style.height = textRef.current.scrollHeight + 'px';
      }, []);
    • ์ด๋ฏธ์ง€์™€ ๊ฒŒ์‹œ๊ธ€์ด ์ค€๋น„๊ฐ€ ๋˜๋ฉด, ๋ฒ„ํŠผ ํด๋ฆญ์„ ํ†ตํ•œ ์ด๋ฒคํŠธ๋กœ ๋ช…์„ธ์— ๋งž๋„๋ก ์„œ๋ฒ„๋กœ ๋ฐ์ดํ„ฐ ์ „์†ก
      • ์ด๋ฏธ์ง€ ์—…๋กœ๋“œ ๋ฒ„ํŠผ์˜ ์Šคํƒ€์ผ์ด ๊ฒŒ์‹œ๋ฌผ ๋“ฑ๋ก๋งŒ ๋‹ฌ๋ผ์„œ, styled-component ์˜ค๋ฒ„๋ผ์ด๋“œ๋ฅผ ํ†ตํ•˜์—ฌ ์ˆ˜์ •
      /* ImageUploadButton.jsx */
      ...
      const ImageUploadButton = ({ className, setUploadImg, uploadImg, inputRef }) => {
      ...
      ...
      return (
      ...
        <ImgUploadButton
          uploadImg={postImages}
          setUploadImg={setUploadImg}
          // ์˜ค๋ฒ„๋ผ์ด๋“œ๋ฅผ ์œ„ํ•˜์—ฌ className ์„ ๋ถ€์—ฌ ( ๋ถ€์—ฌํ•œ ์ด์œ ๋Š” styled-component ๊ฐ€ ์Šคํƒ€์ผ์„ ์ ์šฉํ•˜๋Š” ๋ฐฉ์‹์„ ์ดํ•ดํ•œ๋‹ค๋ฉด ์•Œ ์ˆ˜ ์žˆ๋‹ค. )
          className={className}
          inputRef={inputRef}
        />
      ...
      ...
      const ImgUploadButton = styled(ImageUploadButton)`
        position: fixed;
        margin-left: 26.6rem;
        bottom: 1.6rem;
        width: 5rem;
        height: 5rem;
        background-image: url(${UPLOAD_FILE_ICON});
        background-position: center;
        background-size: cover;
        cursor: pointer;
        z-index: 100;
      `;
  • ๊ฒŒ์‹œ๊ธ€ ์ˆ˜์ •

    1. useParams() ๋ฅผ ํ†ตํ•˜์—ฌ, ํ•ด๋‹น ํŽ˜์ด์ง€์˜ ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ๊ฐ€์ ธ์™€, ํ•ด๋‹นํ•˜๋Š” ๊ฒŒ์‹œ๋ฌผ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ›์•„์˜ด
    2. ๋ฐ›์•„์˜จ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฒŒ์‹œ๊ธ€ ๋“ฑ๋กํŽ˜์ด์ง€์— ๋ฟŒ๋ ค์คŒ
    3. ๋ฟŒ๋ ค์ค€ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€๊ณตํ•˜์—ฌ, ๋‹ค์‹œ PUT ์„ ํ†ตํ•˜์—ฌ ์„œ๋ฒ„์— ์ „์†ก

๋Œ“๊ธ€ ๊ธฐ๋Šฅ ๊ตฌํ˜„
  • ์กฐํšŒ - props ๋กœ ๊ฒŒ์‹œ๊ธ€ ์ •๋ณด๋ฅผ ๋ฐ›์•„์™€, ๊ทธ์•ˆ์— ์ €์žฅ๋œ ๋ฐ์ดํ„ฐ์ค‘ comments ์ •๋ณด๋งŒ์„ ์ •์ œํ•˜์—ฌ ์ƒํƒœ๊ด€๋ฆฌ๋œ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฟŒ๋ ค์ค€๋‹ค.

  • ๋“ฑ๋ก - props ๋กœ ๋ฐ›์•„์˜จ postid ๋ฅผ ํ™œ์šฉํ•˜์—ฌ, ์ค€๋น„๋œ text ์ •๋ณด๋ฅผ ์„œ๋ฒ„์— ์ „์†กํ•œ๋‹ค.

    const sendCommentData = () => {
      axios
        .post(
          `https://mandarin.api.weniv.co.kr/post/${postData.id}/comments`,
          {
            comment: {
              content: `${commentData}`,
            },
          },
          {
            headers: {
              Authorization: `Bearer ${userToken}`,
              'Content-type': 'application/json',
            },
          },
        )
        .then(() => {
          window.location.reload(false);
        });
    };
  • ์‚ญ์ œ ๋ฐ ์‹ ๊ณ 

    • ํ•ด๋‹น ๋Œ“๊ธ€์ด ๋กœ๊ทธ์ธ๋œ ์‚ฌ์šฉ์ž์˜ ๋Œ“๊ธ€์ธ์ง€๋ฅผ ํŒ๋‹จํ•˜์—ฌ, ๋ชจ๋‹ฌ์„ ๋„์šด๋‹ค

      1. ๋กœ๊ทธ์ธ ๋œ ์‚ฌ์šฉ์ž์ผ ๊ฒฝ์šฐ - ์‚ญ์ œ
      const deletePost = () => {
        axios({
          url: url + `/post/${postID}`,
          method: 'DELETE',
          headers: {
            Authorization: `Bearer ${userToken}`,
            'Content-type': 'application/json',
          },
        })
        .then((res) => {
          window.location.replace('/profile');
        })
        .catch((err) => console.error(err));
      };
      1. ๋‹ค๋ฅธ ์‚ฌ์šฉ์ž์˜ ๊ฒฝ์šฐ - ์‹ ๊ณ 
      const reportPost = () => {
          axios({
            url: url + `/post/${postID}/report`,
            method: 'POST',
            headers: {
              Authorization: `Bearer ${userToken}`,
              'Content-type': 'application/json',
            },
          })
          .then((res) => {
            setIsReport(true);
            if (postID === res.data.report.post) {
              setIsReportSuccess(true);
            } else {
              setIsReportSuccess(false);
            }
          })
          .catch((err) => console.error(err));
      };

์ฑ„ํŒ… ๊ธฐ๋Šฅ ๊ตฌํ˜„
  • ์ฑ„ํŒ… ๊ธฐ๋Šฅ ๋ฐฉ์‹

    ๋กœ๊ทธ์ธ๋œ ์‚ฌ์šฉ์ž โ†”ย ์ฑ„ํŒ…๋ฐฉ์œผ๋กœ ์‚ฌ์šฉ๋  ์ œ 3์ž์˜ ๊ฒŒ์‹œ๊ธ€ โ†”ย ์ฑ„ํŒ…ํ•  ์ƒ๋Œ€ ์‚ฌ์šฉ์ž

    โ†’ ์ฑ„ํŒ…๋ฐฉ์œผ๋กœ ์‚ฌ์šฉ๋  ์ œ 3์ž์˜ ์•„์ด๋””๋Š” ์œ ์ € ๊ฒ€์ƒ‰์„ ํ†ตํ•˜์—ฌ ์ฐพ์„ ์ˆ˜ ์—†๋„๋ก ์„ค์ •

    < ์ฑ„ํŒ…๋ฐฉ ์ƒ์„ฑ >

    1. ์ฑ„ํŒ…ํ•  ์ƒ๋Œ€ ์‚ฌ์šฉ์ž์˜ ํ”„๋กœํ•„์—์„œ ์ฑ„ํŒ… ์ด๋ฏธ์ง€ ๋ฒ„ํŠผ์„ ํด๋ฆญํ•˜๋ฉด, ์ฑ„ํŒ…๋ฐฉ์œผ๋กœ ์‚ฌ์šฉ๋  ์ œ 3์ž์˜ ๊ฒŒ์‹œ๊ธ€์ด ์ƒ์„ฑ๋œ๋‹ค.

      // ์ œ 3์ž์˜ ๊ฒŒ์‹œ๊ธ€์„ ๋‹ค๋ฅธ ์œ ์ €๊ฐ€ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ๋„๋ก ํ† ํฐ๊ฐ’์„ ์ง€์ •
      const CHAT_TOKEN = process.env.REACT_APP_CHAT_SERVER_TOKEN;
    2. ์ œ 3์ž์˜ ๊ฒŒ์‹œ๊ธ€์— ์ „์†ก๋˜๋Š” ์ปจํ…์ธ ์ธ ์ฑ„ํŒ… ๋ฐ์ดํ„ฐ โ†’ โ€˜๋กœ๊ทธ์ธ๋œ ์‚ฌ์šฉ์ž์˜ accountname,์ฑ„ํŒ…ํ•  ์ƒ๋Œ€ ์‚ฌ์šฉ์ž์˜ accountnameโ€™

      const createChatroom = () => {
          axios
            .post(
              `https://mandarin.api.weniv.co.kr/post`,
              {
                post: {
                  content: `${userAccountname},${profileUserAccountname}`,
                  image: '',
                },
              },
              {
                headers: {
                  Authorization: `Bearer ${CHAT_TOKEN}`,
                  'Content-type': 'application/json',
                },
              },
            )
            .then((res) => {
              navigate(`/chat/${res.data.post.id}`);
            });
        };

      โ†’ ์ „์†ก๋œ ๋ฐ์ดํ„ฐ๋Š” ์ฑ„ํŒ…๋ฆฌ์ŠคํŠธ๋ฅผ ๋ถˆ๋Ÿฌ์˜ฌ๋•Œ์™€ ์ฑ„ํŒ…๋ฐฉ ์ด๋ฆ„์„ ๋‚˜ํƒ€๋‚ผ๋•Œ ์‚ฌ์šฉํ•œ๋‹ค.

    3. ์ฑ„ํŒ…๋ฐฉ ์ƒ์„ฑ์‹œ, ์ œ 3์ž์˜ ๊ฒŒ์‹œ๊ธ€์˜ content ๋‚ด์šฉ๊ณผ ์ƒ์„ฑํ•  content ๋‚ด์šฉ์ด ์ค‘๋ณต๋œ๋‹ค๋ฉด alert ์ฐฝ์„ ๋„์›Œ์„œ ์ด๋ฏธ ์กด์žฌํ•˜๋Š” ์ฑ„ํŒ…๋ฃธ์ด๋ผ๋Š” ์‚ฌ์‹ค์„ ์‚ฌ์šฉ์ž์—๊ฒŒ ์•Œ๋ฆฐ๋‹ค.

    < ์ฑ„ํŒ…๋ฐฉ ๋ฆฌ์ŠคํŠธ >

    • ์ œ 3์ž์˜ ๊ฒŒ์‹œ๊ธ€์˜ ์ •๋ณด๋ฅผ ๋ถˆ๋Ÿฌ์™€, ์ „์†ก๋œ ์ปจํ…์ธ  ๋ฐ์ดํ„ฐ ์— ์‚ฌ์šฉ์ž์˜ accountname ์ด ํฌํ•จ๋œ ๊ฒŒ์‹œ๊ธ€๋งŒ ๋ณด์—ฌ์ค€๋‹ค.

    < ์ฑ„ํŒ…๋ฐฉ >

    • useParams() ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ, ์„ ํƒํ•œ url์˜ ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜จ ํ›„, ๊ทธ ํŒŒ๋ผ๋ฏธํ„ฐ(postid) ์— ํ•ด๋‹นํ•˜๋Š” ๊ฒŒ์‹œ๊ธ€์„ ๋ถˆ๋Ÿฌ์˜จ๋‹ค. ์—ฌ๊ธฐ์— ์ž‘์„ฑ๋œ ๋Œ“๊ธ€์ด ๋ณธ์ธ์˜ ๊ฒƒ์ด๋ผ๋ฉด, ๋ณธ์ธ์ด ๋‚ ๋ฆฐ ์ฑ„ํŒ…์œผ๋กœ ๋ณด์—ฌ์ง€๊ณ , ์•„๋‹ˆ๋ผ๋ฉด ํƒ€ ์‚ฌ์šฉ์ž๊ฐ€ ๋ณด๋‚ธ ์ฑ„ํŒ…์ฒ˜๋Ÿผ ๋ณด์—ฌ์ง„๋‹ค.

    < ์ฑ„ํŒ… >

    • ์ฑ„ํŒ…๋ฐฉ์— ์ž…์žฅํ•˜๋ฉด, ์ฑ„ํŒ…๋ฐฉ์œผ๋กœ ์‚ฌ์šฉ๋œ ๊ฒŒ์‹œ๋ฌผ์— ๋Œ“๊ธ€ ํ˜•์‹์œผ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ์ „์†กํ•œ๋‹ค.

(Top)


12. ๋Š๋‚€์ 

๐Ÿฐ ๊น€๋ฏผ์Šน

์ด๋ฒˆ ํŒ€ํ”„๋กœ์ ํŠธ๋Š” ์ œ๊ฒŒ๋Š” ๋„ˆ๋ฌด ํ–‰๋ณตํ•˜๊ณ  ๊ท€ํ•œ ๊ฒฝํ—˜์ด์—ˆ์Šต๋‹ˆ๋‹ค. ๊ฒฝํ—˜ ๋งŽ์€ ํŒ€์žฅ๋‹˜์ด ํŒ€์›๋“ค์„ ์œ„ํ•ด ์ œ๊ฐ€ ์ƒ๊ฐ์น˜๋„ ๋ชปํ•˜๋Š” ๋ถ€๋ถ„์„ ๋ฏธ๋ฆฌ ์ค€๋น„ํ•ด์ฃผ์‹œ๋Š” ๋ชจ์Šต๋„ ๋„ˆ๋ฌด ์ธ์ƒ๊นŠ์—ˆ๊ณ  ๊ฐœ๋ฐœํ•˜๋ฉด์„œ ๊ทธ๊ฒƒ์„ ์ •๋ง ํŽธํ•˜๊ฒŒ ํ™œ์šฉํ–ˆ์Šต๋‹ˆ๋‹ค. ๋ฏธ๋ž˜์— ํ”„๋กœ์ ํŠธ ํŒ€์žฅ์„ ๋งก๊ฒŒ ๋œ๋‹ค๋ฉด ๋ฐฐ์šฐ๊ณ  ์‹ถ์—ˆ๋˜ ๋ถ€๋ถ„์ด ๋งŽ์•˜์Šต๋‹ˆ๋‹ค. ๋Šฅ๋ ฅ์žˆ๋Š” ํŒ€์›๋ถ„๋“ค์˜ ์ฝ”๋“œ๋ฅผ ๋ณด๋ฉฐ ๋™๊ธฐ๋ถ€์—ฌ๋„ ๋งŽ์ด ๋๊ณ  ์ œ๊ฐ€ ์ž˜ ์•Œ์ง€ ๋ชปํ•˜๋Š”์ ์„ ์บ์น˜ํ•˜๊ณ  ์„ผ์Šค์žˆ๊ฒŒ ์•Œ๋ ค์ฃผ๋Š” ๋ชจ์Šต์—๋„ ํฐ ์šฉ๊ธฐ๋ฅผ ์–ป์—ˆ์Šต๋‹ˆ๋‹ค. ํŒ€์›๋“ค๊ณผ ๋ถ€์กฑํ•œ ๋ถ€๋ถ„์„ ์ฑ„์›Œ์ฃผ๋ฉฐ ํ”„๋กœ์ ํŠธ๋ฅผ ์ž˜ ๋งˆ๋ฌด๋ฆฌํ•œ๊ฒƒ ๊ฐ™์•„ ๊ธฐ์ฉ๋‹ˆ๋‹ค. ๊ธ์ •์ ์ธ ํŒ€์˜ ๋ถ„์œ„๊ธฐ์— ์•ˆ์ข‹์€ ์˜ํ–ฅ์„ ๋ผ์น˜์ง€ ์•Š์œผ๋ ค๊ณ  ํ‰์†Œ๋ณด๋‹ค ๋ช‡๋ฐฐ๋กœ ๋” ์—ด์‹ฌํžˆ ํ•  ์ˆ˜ ์žˆ์—ˆ์œผ๋ฉฐ ๊ทธ๋กœ์ธํ•ด ๊ฐœ์ธ์ ์œผ๋กœ๋„ ํฐ ์„ฑ์žฅ์„ ์ด๋ฃฌ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค. ์ด๋ฒˆ ํŒ€ํ”„๋กœ์ ํŠธ๋ฅผ ํ†ตํ•ด ์ œ๊ฐ€ ์–ด๋–ค ๋ฐฉํ–ฅ์œผ๋กœ ๋‚˜์•„๊ฐ€๋Š”์ง€, ๊ฐœ๋ฐœ๊ณผ ํ”„๋กœ์ ํŠธ๋Š” ์–ด๋–ค์‹์œผ๋กœ ํ•ด์•ผํ•˜๋Š”์ง€์— ๋Œ€ํ•œ ํฐ ์˜๊ฐ์„ ์–ป์—ˆ์Šต๋‹ˆ๋‹ค. ํ•จ๊ป˜ ๊ณ ์ƒํ•œ ํŒ€์›๋“ค๊ป˜ ๋„ˆ๋ฌด๋„ˆ๋ฌด ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค!!


๐Ÿฆ’ ๊น€์˜ํ˜ธ

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


๐Ÿฃ ๋ฐฐ์Šน์—ฐ

ํ”„๋ก ํŠธ์—”๋“œ์Šค์ฟจ ๊ธฐ๊ฐ„ ๋™์•ˆ ์ด๋ฃจ๊ณ  ์‹ถ์—ˆ๋˜ ๊ฐœ์ธ์ ์ธ ๋ชฉํ‘œ๊ฐ€ 3๊ฐœ ์žˆ์—ˆ๋Š”๋ฐ์š”. ์ฒซ ๋ฒˆ์งธ๊ฐ€ ํ˜‘์—… ๊ฐ€๋Šฅํ•  ๋งŒํผ GitHub ์ตํžˆ๊ธฐ, ๋‘ ๋ฒˆ์งธ๊ฐ€ ํŒ€ ํ”„๋กœ์ ํŠธ ์‹œ ESLint&Prettier ์ ์šฉํ•ด๋ณด๊ธฐ, ์„ธ ๋ฒˆ์งธ๊ฐ€ ํŒ€ ํ”„๋กœ์ ํŠธ ์ž˜ ๋งˆ๋ฌด๋ฆฌํ•˜๊ธฐ์˜€์Šต๋‹ˆ๋‹ค. ์ด๋ฒˆ ๊ฐ€์ ธ๋„๋Œ•๋ƒฅ ํ”„๋กœ์ ํŠธ๋ฅผ ์ง„ํ–‰ํ•˜๋ฉด์„œ ์ œ๊ฐ€ ์ด๋ฃจ๊ณ  ์‹ถ์—ˆ๋˜ ๋ชฉํ‘œ 3๊ฐœ๋ฅผ ๋ชจ๋‘ ๋‹ฌ์„ฑํ•˜๊ฒŒ ๋˜์–ด ํ–‰๋ณตํ•ฉ๋‹ˆ๋‹ค.

์ด๋ฒˆ ํ”„๋กœ์ ํŠธ๋ฅผ ํ†ตํ•ด ํŒ€์ด๊ธฐ์— ํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒฝํ—˜์„ ๋งŽ์ด ํ–ˆ์Šต๋‹ˆ๋‹ค. ์ด์Šˆ ๊ด€๋ฆฌ ํ”„๋กœ์„ธ์Šค์™€ ๋ฒ„๊ทธ ๊ด€๋ฆฌ ํ”„๋กœ์„ธ์Šค๋ฅผ ์„ธ์›Œ ์šฐ๋ฆฌ ํŒ€์˜ ๋ฌธํ™”๋กœ ๋งŒ๋“  ๊ฒƒ, ๋‹ค๋ฅธ ๋ถ„๋“ค์˜ ์ฝ”๋“œ๋ฅผ ์ฝ๋Š” ๊ฒƒ์— ๋‘๋ ค์›€์ด ์žˆ์—ˆ๋˜ ์ œ๊ฐ€ ๋‹ค๋ฅธ ๋ถ„๋“ค์˜ PR์„ ๋ณด๋ฉฐ ๋ฆฌ๋ทฐ๋ฅผ ๋“œ๋ฆฐ ๊ฒƒ, ๋ชจ๋‘ ํ•ฉ์‹ฌํ•˜์—ฌ ์ฝ”๋”ฉ ์ปจ๋ฒค์…˜์„ ๋งŒ๋“ค๊ณ  ์ •ํ•ด์ง„ ์ปจ๋ฒค์…˜๋Œ€๋กœ ํ”„๋กœ์ ํŠธ ์ดˆ๊ธฐ ์„ธํŒ…์„ ํ•ด๋ณธ ๊ฒƒ. ๋ชจ๋‘ ํ˜ผ์ž์˜€์œผ๋ฉด ํ•˜์ง€ ๋ชปํ•  ์†Œ์ค‘ํ•œ ๊ฒฝํ—˜๋“ค์ด์—ˆ์Šต๋‹ˆ๋‹ค.

ํŒ€์žฅ ์ž๋ฆฌ๋ฅผ ๋งก๊ฒŒ ๋˜์–ด ๋ถ€๋‹ด์ด ๋งŽ์ด ๋์—ˆ๋Š”๋ฐ, ์˜คํžˆ๋ ค ์ด ๋ถ€๋‹ด์ด ์ €์—๊ฒŒ ์ข‹์€ ๋ฐฉํ–ฅ์œผ๋กœ ์ž‘์šฉํ•œ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค! ๋งˆ์ง€๋ง‰์œผ๋กœ ๋Š์ž„์—†๋Š” ์นญ์ฐฌ์œผ๋กœ ์ €๋ฅผ ์ถค์ถ”๊ฒŒ ํ•ด์ฃผ์…จ๋˜ ํŒ€์›๋ถ„๋“ค๊ป˜ ์ •๋ง ๊ฐ์‚ฌ๋“œ๋ฆฝ๋‹ˆ๋‹ค. ์ € ํ˜ผ์ž์˜€๋‹ค๋ฉด ํ•  ์ˆ˜ ์—†์—ˆ์„ํ…๋ฐ ์˜ค๋ฅ˜๊ฐ€ ๋‚˜๋ฉด ๋‹ค ํ•จ๊ป˜ ํ•ด๊ฒฐํ•˜๊ณ , ์•ˆ๋˜๋Š” ๊ฒŒ ์žˆ์œผ๋ฉด ๋ฐค์„ ์ƒˆ๊ฐ€๋ฉฐ ์–ด๋–ป๊ฒŒ๋“  ํ•ด๋‚ด๋Š” ํŒ€์›๋ถ„๋“ค์˜ ์—๋„ˆ์ง€์™€ ์—ด์ • ๋•๋ถ„์— ์™„์ฃผํ•  ์ˆ˜ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.


๐ŸŒธ ์ด๊ด‘๋ ฌ

ํ”„๋กœ์ ํŠธ๋ฅผ ์ง„ํ–‰ํ•˜๋ฉด์„œ ํŒ€์›๋ถ„๋“ค์˜ ์•„๋‚Œ์—†๋Š” ์‘์›์†์—์„œ ๋‹คํ•จ๊ป˜ ์„ฑ์žฅํ•˜๋Š” ๊ธฐ๋ถ„์„ ๋Š๋‚„ ์ˆ˜ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค. ์ฒ˜์Œ์—๋Š” ๋‹จ์ˆœํ•œ ํผ๋ธ”๋ฆฌ์‹ฑ๋„ ๋จธ๋ญ‡ํ•œ ์ €์˜€๋Š”๋ฐ, ํ˜ผ์ž ๊ณ ๋ฏผํ•˜๋Š” ๊ณผ์ •์„ ๊ฑฐ์น˜๊ณ  ํŒ€์›๋ถ„๋“ค๊ณผ ์„œ๋กœ ์†Œํ†ต์„ ํ†ตํ•˜์—ฌ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•ด ๋‚˜๊ฐ€๋‹ค ๋ณด๋‹ˆ ์ด์ œ๋Š” ํ•˜๋‚˜์˜ ๊ธฐ๋Šฅ์€ ๋ฌผ๋ก , ์—ฌ๋Ÿฌ ๊ธฐ๋Šฅ์„ ๊ตฌํ˜„ํ•˜๋Š”๊ฒƒ์— ์žˆ์–ด ์ž์‹ ๊ฐ์ด ์ƒ๊ธด ๊ณ„๊ธฐ๊ฐ€ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ์„œ๋กœ ๊ถ๊ธˆํ•œ ๋ถ€๋ถ„์ด ์žˆ์œผ๋ฉด, ๊ฐ™์ด ๊ณ ๋ฏผํ•ด์ฃผ๊ณ  ํ•ด๊ฒฐํ•˜๋Š” ํŒ€ ๋ถ„์œ„๊ธฐ๊ฐ€ ๋„ˆ๋ฌด ๋”ฐ๋“ฏํ•˜๊ณ  ํ–‰๋ณตํ–ˆ์Šต๋‹ˆ๋‹ค. ์ž‘๊ฒŒ๋Š”, styled-component ๋ฅผ ์–ด๋Š ๋‹จ์œ„๋กœ ์ชผ๊ฐœ์•ผ ํ•˜๋Š” ์ง€ ์ €ํฌ ํŒ€์› ๋ชจ๋‘ ๊ณ ๋ฏผํ•˜์—ฌ ์ €ํฌ์—๊ฒŒ ์ ํ•ฉํ•œ ๋ฐฉ๋ฒ•์„ ์ฐฉ์•ˆ์„ ํ–ˆ์—ˆ๊ณ , ํฌ๊ฒŒ๋Š” ๋ฌดํ•œ๋ Œ๋”์™€ ๊ด€๋ จ๋œ ๋ถ€๋ถ„๋„ ๋‹คํ•จ๊ป˜ ์นจ์ฐฉํ•˜๊ฒŒ ํ™”๋ฉด๊ณต์œ ๋ฅผ ํ•˜๋ฉฐ ํ•ด๊ฒฐ์„ ํ•ด ๋‚˜๊ฐ”์Šต๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ์„œ๋กœ ํ˜‘์—…ํ•˜๊ณ  ํ•ด๊ฒฐํ•ด ๋‚˜๊ฐ€๋Š” ๊ณผ์ •์„ ํ•œ๋‹ฌ๋™์•ˆ ์ง€์†ํ•˜๋‹ค๋ณด๋‹ˆ ํ˜‘์—…์˜ ์ค‘์š”์„ฑ์„ ๋Š๋ผ๋ฉฐ, ์„ฑ์žฅํ•ด ๋‚˜์•„๊ฐ€์•ผํ•  ๋ฐฉ๋ฒ•์„ ์•Œ๊ฒŒ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ๊ฐ€๋”์€ ์ง€์น˜๊ณ  ํž˜๋“  ๋‚ ๋„ ์žˆ์—ˆ์ง€๋งŒ, ํŒ€์›๋“ค์˜ ์—ด์ •์— ์ €๋„ ๋ชจ๋ฅด๊ฒŒ ์›ƒ์œผ๋ฉด์„œ ๋‹ค์‹œ ํ•œ๋ฒˆ ํž˜์„ ์–ป์–ด ํ”„๋กœ์ ํŠธ๋ฅผ ์ง„ํ–‰ํ•˜์˜€์Šต๋‹ˆ๋‹ค.

๋‹ค๋ฅธ ๋ณต์€ ๋ชฐ๋ผ๋„ ํ•ญ์ƒ ์ฃผ๋ณ€ ์ธ๋ณต์€ ๋งŽ๋‹ค๊ณ  ์ƒ๊ฐํ•˜๋ฉด์„œ ์‚ด์•„์™”๋Š”๋ฐ, ์ด๋ฒˆ ํ”„๋กœ์ ํŠธ ์—ญ์‹œ ํƒ€๊ณ ๋‚œ ์ธ๋ณต ๋•๋ถ„์— ์ข‹์€ ํŒ€์›๋ถ„๋“ค๊ณผ ๋”ฐ๋“ฏํ•œ ๋ถ„์œ„๊ธฐ ์†์— ์„œ๋กœ ์„ฑ์žฅํ•˜๊ณ  ์ข‹์€ ์‹œ๊ฐ„์„ ๋ณด๋ƒˆ์Šต๋‹ˆ๋‹ค! ์ด ์†Œ์ค‘ํ–ˆ๋˜ ์‹œ๊ฐ„์„ ๊ผญ ๊ธฐ์–ตํ•˜์—ฌ, ํ˜ผ์ž ์„ฑ์žฅํ•˜๋Š” ๊ฐœ๋ฐœ์ž๊ฐ€ ์•„๋‹Œ ํ•จ๊ป˜ ์„ฑ์žฅํ•˜๋Š” ๊ฐœ๋ฐœ์ž๊ฐ€ ๋˜๋„๋ก ๋…ธ๋ ฅํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค! ๊ทธ๋™์•ˆ ํ•จ๊ป˜ ๊ณ ์ƒํ•ด์ค€ ํŒ€์›๋“ค ๋„ˆ๋ฌด ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค~!!!๐ŸŒธ


(Top)


13. ํ”„๋กœ์ ํŠธ ๋ฐœํ‘œ ์ž๋ฃŒ ๋ฐ ์‹œ์—ฐ ์˜์ƒ


(Top)


Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.