Skip to content

๐ŸŽจ ์ˆ˜์ˆ˜๋งˆ์ผ“ ์˜ˆ์ˆ ์ž‘ํ’ˆ์„ ์‚ฌ๋ž‘ํ•˜๋Š” ์‚ฌ๋žŒ๋“ค์„ ์œ„ํ•œ SNS/์ปค๋ฎค๋‹ˆํ‹ฐ ์„œ๋น„์Šค์ž…๋‹ˆ๋‹ค.

Notifications You must be signed in to change notification settings

FRONTENDSCHOOL5/final-24-Susumarket

Folders and files

NameName
Last commit message
Last commit date

Latest commit

ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 

Repository files navigation

์ˆ˜์ˆ˜๋งˆ์ผ“

๐Ÿ“Ž ๋ฐฐํฌ URL


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


๐Ÿ“ƒ ๋ชฉ์ฐจ (ํด๋ฆญ ์‹œ ํ•ด๋‹น ๋ชฉ์ฐจ๋กœ ์ด๋™ํ•ฉ๋‹ˆ๋‹ค.)

1.๐ŸŽจ ํ”„๋กœ์ ํŠธ ์†Œ๊ฐœ

์ˆ˜์ˆ˜๋งˆ์ผ“์€ ์˜ˆ์ˆ ์ž‘ํ’ˆ์„ ์‚ฌ๋ž‘ํ•˜๋Š” ์‚ฌ๋žŒ๋“ค์„ ์œ„ํ•œ SNS/์ปค๋ฎค๋‹ˆํ‹ฐ ์„œ๋น„์Šค์ž…๋‹ˆ๋‹ค.

๊ธฐํš ์˜๋„

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

๊ฐœ๋ฐœ ๋™๊ธฐ

  • ์ž์‹ ์˜ ์˜ˆ์ˆ ํ’ˆ์„ ์†์‰ฝ๊ฒŒ ์‚ฌ๊ณ ํŒ” ์ˆ˜ ์žˆ๋Š” ํ”Œ๋žซํผ์„ ํ†ตํ•ด ์•„๋งˆ์ถ”์–ด๋“ค์—๊ฒŒ ๊ธฐํšŒ ์ฐฝ์ถœ
  • ์ผ๋ฐ˜ ์‚ฌ๋žŒ๋“ค๋„ ๋ฌธํ™”๋ฅผ ์ข€ ๋” ๊ฐ€๊นŒ์ด ์ฆ๊ธธ ์ˆ˜ ์žˆ๋„๋ก ํ•˜์ž!

TOP ๐Ÿ”ผ


2.๐Ÿ‘ฉโ€๐ŸŽจ 24์‹œ๊ฐ„์ด ๋ชจ์ž๋ผ์กฐ ํŒ€์› ์†Œ๊ฐœ

FE ๊ฐ•์œค์ • FE ๋‚จ์ข…ํƒœ FE ์•ˆ๋‚˜๋ณ„ FE ์–‘์„œ์ง„
๐Ÿ”— GitHub
๋””์ž์ธ ๋ฆฌ๋”
๐Ÿ”— GitHub
๊ฐœ๋ฐœ ๋ฆฌ๋”
๐Ÿ”— GitHub
ํŒ€์žฅ
๐Ÿ”— GitHub
๋…ธ์…˜/์ •๋ฆฌ ์ฑ…์ž„

TOP ๐Ÿ”ผ


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

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

  • IDE : Visual Studio Code 1.74.2
  • OS : Windows 10
๊ตฌ๋ถ„ ์„ค๋ช…
FrontEnd
BackEnd ์ œ๊ณต๋œ API ์‚ฌ์šฉ
ํ˜‘์—… ๋„๊ตฌ
IDE

3-2. ๋งํฌ

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

3-3 Version

react: ^18.2.0
react-router-dom: ^6.12.1
axios: ^1.4.0
styled-components: ^5.3.11
styled-reset: ^4.4.7
react-device-detect: ^2.2.3
lodash: ^4.17.21
prettier: 2.8.8

TOP ๐Ÿ”ผ


4.๐Ÿ“† ๊ฐœ๋ฐœ ์ผ์ •

๐Ÿ”ฅ 2023-06-02 ~ 2023-06-27

image

ํŒ€ ๋ฏธํŒ…, ํ”„๋กœ์ ํŠธ ๊ณ„ํš : 2023-06-02 ~ 2023-06-05
  • ์•„์ด์Šค ๋ธŒ๋ ˆ์ดํ‚น
  • ํ”„๋กœ์ ํŠธ ์ฃผ์ œ ํ† ์˜
  • ์‚ฌ์šฉ ๊ธฐ์ˆ  ์Šคํƒ์ •ํ•˜๊ธฐ
  • ๊ฐœ์ธ ๊ณต๋ถ€
  • ๊นƒ&๊นƒํ—™ ์ „๋žต ์ดํ•ด
์ปจ๋ฒค์…˜ ๋ฐ apiํ•™์Šต์„ ์œ„ํ•œ ์‚ฌ์ „๊ณผ์ œ(๋‚ ์”จ์•ฑ) ์ง„ํ–‰ : 2023-06-08 ~ 2023-06-11
์‚ฌ์ „๊ณผ์ œ(๋‚ ์”จ์•ฑ)์„ ํ•จ์œผ๋กœ์จ ์–ป์—ˆ๋˜ ์ด์  ๊ธฐ๋Œ€ํšจ๊ณผ ํ”„๋กœ์ ํŠธ์— ์‚ฌ์šฉ๋˜๋Š” ๊ธฐ๋Šฅ์„ ๋ฏธ๋ฆฌ ์‚ฌ์šฉํ•ด๋ด„์œผ๋กœ์จ ์งํ›„ 1์ฐจ ๊ธฐ๋Šฅ ๊ตฌํ˜„ํ•  ๋•Œ ๋„์›€์ด ๋จ
์ฝ”๋“œ ์ปจ๋ฒค์…˜ ์—ฐ์Šต
API ๋น„๋™๊ธฐ ์ดํ•ด
styled-component ํ•™์Šต
๋‚ ์”จ์•ฑ ๋ ˆํฌ์ง€ํ† ๋ฆฌ https://github.com/24-test-project/weatherapp
์š”๊ตฌ์‚ฌํ•ญ ํŒŒ์•… ๋ฐ ํ”„๋กœ์ ํŠธ ๊ทœ์น™ ์„ค๋ฆฝ : 2023-06-08 ~ 2023-06-12
  • ํŒ€ ๊ทœ์น™
  • ๊ธฐํš, ๋””์ž์ธ
  • prettier ์„ค์ •
  • ์ฝ”๋“œ ์ปจ๋ฒค์…˜ ์„ค์ •
  • git ์ปจ๋ฒค์…˜ ์„ค์ •
  • ํด๋” ๊ตฌ์กฐ
  • ๊ณตํ†ต ์ปดํฌ๋„ŒํŠธ ์ง€์ •
  • GlobalStyle ์„ค์ •
๊ณตํ†ตUI ์ปดํฌ๋„ŒํŠธ ๊ฐœ๋ฐœ : 2023-06-12 ~ 2023-06-14
    ํ•จ๊ป˜ ๊ฐ™์ด ๋งŒ๋“ค์—ˆ๋˜ ๊ฒƒ
  • ์—๋Ÿฌ ๋ฉ”์‹œ์ง€
  • ์Šคํ”Œ๋ž˜์‹œ ํ™”๋ฉด ๊ฐœ๋ฐœ
  • ๋กœ๊ทธ์ธ ์‹œ์ž‘ ํŽ˜์ด์ง€ ๊ฐœ๋ฐœ
1์ฐจ ๊ฐœ๋ฐœ : 2023-06-14 ~ 2023-06-19
2์ฐจ ๊ฐœ๋ฐœ : 2023-06-19 ~ 2023-06-24

ํŒ”๋กœ์šฐ ์ข‹์•„์š” ๊ฒŒ์‹œ๋ฌผ์ž‘์„ฑ(3๊ฐœ๊นŒ์ง€) ์บ”๋ฒ„์Šค ๋Œ“๊ธ€

๋ฒ„๊ทธ ์ˆ˜์ • ๋ฐ ์œ ์ง€๋ณด์ˆ˜ : 2023-06-24 ~ 2023-06-27
"
์ถ”๊ฐ€ ๊ตฌํ˜„ ๋ฐ ๋ฐฐํฌ : 2023-06-26 ~ 2023-06-28
"

TOP ๐Ÿ”ผ

5.๐Ÿ“Œ Git Branch ์ „๋žต

GitBranch

  • ์†Œ๊ทœ๋ชจ ํ”„๋กœ์ ํŠธ์— ๋งž๊ฒŒ Main, Develop, Feature ์„ธ Branch๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์ „๋žต ์‚ฌ์šฉ
  • Merge ๋Œ€์‹  Rebase๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ณด๊ธฐ ์ข‹์€ ์ปค๋ฐ‹ ํžˆ์Šคํ† ๋ฆฌ๋ฅผ ์œ ์ง€ํ•จ

๐Ÿ˜† Git&GitHub ๊ฐ€์ด๋“œ ๋ฌธ์„œ์ž‘์„ฑ

image image image image


TOP ๐Ÿ”ผ



6.๐Ÿ“… ํ”„๋กœ์ ํŠธ ๊ด€๋ฆฌ ๋ฐ ์ง„ํ–‰

๐Ÿ“Š ํ”„๋กœ์ ํŠธ ์ง„ํ–‰ ์ƒํ™ฉ ๊ด€๋ฆฌ

  • ๐Ÿ”˜ GitHub Issues
    • ๊ฐ„ํŽธํ•œ ์ด์Šˆ ์ƒ์„ฑ์„ ์œ„ํ•ด ์ด์Šˆ ํ…œํ”Œ๋ฆฟ์„ ๋งŒ๋“ค์–ด ์‚ฌ์šฉํ–ˆ์Šต๋‹ˆ๋‹ค.
    • ์ด์Šˆ ํ…œํ”Œ๋ฆฟ์œผ๋กœ ์–ด๋–ค ์ด์Šˆ์ธ์ง€, ์–ด๋–ค ํŽ˜์ด์ง€์— ํ•ด๋‹นํ•˜๋Š” ์ง€, ๊ตฌํ˜„ ํ•ด์•ผ ํ•˜๋Š” ๋‚ด์šฉ์ด ๋ฌด์—‡์ธ์ง€๋ฅผ ์ ๋„๋ก ํ–ˆ์Šต๋‹ˆ๋‹ค.
    • ํŒ€์›์ด ํ˜„์žฌ ์–ด๋–ค ์ž‘์—…์„ ์ง„ํ–‰ํ•˜๊ณ  ์žˆ๋Š”์ง€๋ฅผ ๋ฐ”๋กœ ์•Œ ์ˆ˜ ์žˆ์–ด ์˜์‚ฌ์†Œํ†ต ๋น„์šฉ์„ ์ค„์ผ ์ˆ˜ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค. image
  • ๐Ÿ—‚๏ธ GitHub Projects
    • ์นธ๋ฐ˜ ๋ณด๋“œ๋ฅผ ์‚ฌ์šฉํ•ด ํ”„๋กœ์ ํŠธ ์ง„ํ–‰ ์ƒํ™ฉ์„ ํ•œ ๋ˆˆ์— ํ™•์ธํ•  ์ˆ˜ ์žˆ์–ด ์ผ์ •์„ ๊ด€๋ฆฌํ•˜๊ธฐ ์ˆ˜์›”ํ–ˆ์Šต๋‹ˆ๋‹ค. image

TOP ๐Ÿ”ผ


๐Ÿš€ GitHub Action - ๋ธŒ๋žœ์น˜ ์ƒ์„ฑ ์ž๋™ํ™”

image

  • Create Issue Branch
  • ์ด์Šˆ๋ฅผ ์ƒ์„ฑํ•˜๋ฉด GitHub Action์œผ๋กœ ํ•ด๋‹น ์ด์Šˆ์— ํ•ด๋‹นํ•˜๋Š” ๋ธŒ๋žœ์น˜๊ฐ€ ์ž๋™์œผ๋กœ ์ƒ์„ฑ๋˜๋„๋ก ์„ค์ •ํ•˜์—ฌ ๋ธŒ๋žœ์น˜๋ช…์„ ๊ณ ๋ฏผํ•˜๊ณ  ๋ธŒ๋žœ์น˜๋ฅผ ์ƒ์„ฑํ•˜๋Š” ์‹œ๊ฐ„์„ ์ค„์˜€์Šต๋‹ˆ๋‹ค.
    • ๋ธŒ๋žœ์น˜ ์ž๋™ํ™” ์„ค์ • ์ƒ์„ธ ๋‚ด์šฉ
  • ์˜ˆ) ์ž๋™ ์ƒ์„ฑ๋œ ๋ธŒ๋žœ์น˜๋ฅผ pull ํ•˜๊ณ  git checkout -t origin/feat/issue-81ํ•˜์—ฌ ํ•ด๋‹น ๋ธŒ๋žœ์น˜๋กœ ์ด๋™ํ•ฉ๋‹ˆ๋‹ค.

TOP ๐Ÿ”ผ


๐Ÿ“ ์ปจ๋ฒค์…˜

ํŒ€์› ๊ฐ„์˜ ์›ํ™œํ•œ ์†Œํ†ต๊ณผ ํ˜‘์—…์„ ์œ„ํ•ด ์ปค๋ฐ‹ ์ปจ๋ฒค์…˜๊ณผ, ์ฝ”๋“œ ์ปจ๋ฒค์…˜์„ ๋งŒ๋“ค์–ด ์ด๋ฅผ ๋”ฐ๋ž์Šต๋‹ˆ๋‹ค.

๐Ÿ”— ์ปค๋ฐ‹ ์ปจ๋ฒค์…˜

  • ๋‹ค์–‘ํ•œ ์‚ฌ๋ก€๋ฅผ ์ฐธ๊ณ ํ•˜์—ฌ ํ”„๋กœ์ ํŠธ์—์„œ ์ฃผ๋กœ ์“ฐ์ผ ๊ฒƒ ๊ฐ™์€ ์ปค๋ฐ‹ ์œ ํ˜•์„ ๊ฐ„์ถ”๋ ค ์ปจ๋ฒค์…˜์œผ๋กœ ์ง€์ •ํ–ˆ์Šต๋‹ˆ๋‹ค.

    1. ์ปค๋ฐ‹ ์œ ํ˜• ์ง€์ •
        - ์ปค๋ฐ‹ ์œ ํ˜•์€ ์˜์–ด๋กœ ์ž‘์„ฑํ•˜๋ฉฐ, ์ฒซ ๊ธ€์ž๋ฅผ ๋Œ€๋ฌธ์ž๋กœ ํ•ฉ๋‹ˆ๋‹ค
        - ์ปค๋ฐ‹ ์œ ํ˜•
        - Feat : ์ƒˆ๋กœ์šด ๊ธฐ๋Šฅ, ํŠน์ง• ์ถ”๊ฐ€
        - Fix : ์ˆ˜์ •, ๋ฒ„๊ทธ ์ˆ˜์ •
        - Docs : ๋ฌธ์„œ์— ๊ด€๋ จ๋œ ๋‚ด์šฉ, ๋ฌธ์„œ ์ˆ˜์ •
        - Style : ์Šคํƒ€์ผ๋ง
        - Refactor : ๋ฆฌํŒฉํ† ๋ง
        - Test : ํ…Œ์ŠคํŠธ ์ฝ”๋“œ ์ˆ˜์ •, ๋ˆ„๋ฝ๋œ ํ…Œ์ŠคํŠธ๋ฅผ ์ถ”๊ฐ€ํ•  ๋•Œ, ๋ฆฌํŒฉํ† ๋ง ํ…Œ์ŠคํŠธ ์ถ”๊ฐ€
    	- Remove : ํŒŒ์ผ์„ ์‚ญ์ œํ•˜๋Š” ์ž‘์—…๋งŒ ์ˆ˜ํ–‰ํ•œ ๊ฒฝ์šฐ
    	- Comment : ํ•„์š”ํ•œ ์ฃผ์„ ์ถ”๊ฐ€ ๋ฐ ๋ณ€๊ฒฝ
    	- Rename : ํŒŒ์ผ ํ˜น์€ ํด๋”๋ช…์„ ์ˆ˜์ •ํ•˜๊ฑฐ๋‚˜ ์˜ฎ๊ธฐ๋Š” ์ž‘์—…๋งŒ์ธ ๊ฒฝ์šฐ
    	- init : ์ดˆ๊ธฐ ํŒŒ์ผ ์„ค์ •
        - Chore : ๋นŒ๋“œ ์—…๋ฌด ์ˆ˜์ •, ํŒจํ‚ค์ง€ ๋งค๋‹ˆ์ € ์ˆ˜์ •
    
    ๐Ÿงพ 2. ์ปค๋ฐ‹ ๋ฉ”์‹œ์ง€๋Š” ์ œ๋ชฉ & ๋ณธ๋ฌธ์œผ๋กœ ๊ตฌ์„ฑํ•ฉ๋‹ˆ๋‹ค.
    
        git commit -m "Feat: ๋กœ๊ทธ์ธ ๊ธฐ๋Šฅ ๊ตฌํ˜„ #13 //์ œ๋ชฉ
            - ๋กœ๊ทธ์ธ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ //๋ณธ๋ฌธ
            - ๋กœ๊ทธ์ธ ์ •๋ณด ์„œ๋ฒ„๋กœ ์ „์†ก" //๋ณธ๋ฌธ
    
    ๐Ÿ‘† 3. ํ•œ ์ปค๋ฐ‹์—๋Š” ํ•œ ๊ฐ€์ง€ ๋ฌธ์ œ๋งŒ ๋‹ด์Šต๋‹ˆ๋‹ค.
    

๐Ÿ”— ์ฝ”๋“œ ์ปจ๋ฒค์…˜

  • ๋ฆฌ์•กํŠธ ์ฝ”๋”ฉ์— ์ฃผ๋กœ ์“ฐ์ด๋Š” ์ปจ๋ฒค์…˜์„ ์ฐธ๊ณ ํ•˜์—ฌ ์ €ํฌ ์กฐ๋งŒ์˜ ์ฝ”๋“œ ์ปจ๋ฒค์…˜์„ ๋งŒ๋“ค์—ˆ์Šต๋‹ˆ๋‹ค.

  • ๋ฌธ์ž์—ด ์ฒ˜๋ฆฌ ์‹œ ์Œ๋”ฐ์˜ดํ‘œ/ํ™‘๋”ฐ์˜ดํ‘œ์˜ ์‚ฌ์šฉ, ํ˜น์€ ๋ฌธ์žฅ ๋ ์„ธ๋ฏธ์ฝœ๋ก ์˜ ์‚ฌ์šฉ์—ฌ๋ถ€์™€ ๊ฐ™์€ ๊ฐœ์ธ์  ์ทจํ–ฅ์ด ๋ฐ˜์˜๋  ์ˆ˜ ์žˆ๋Š” ํ•ญ๋ชฉ๋“ค์˜ ๊ฒฝ์šฐ์—๋Š” ์‚ฌ์ „ ์„ค๋ฌธ์„ ํ†ตํ•ด ๋‹ค์ˆ˜๊ฒฐ์— ๋”ฐ๋ผ ์ง€์ •ํ–ˆ์Šต๋‹ˆ๋‹ค.

    ๐Ÿ›ผ ์ปดํฌ๋„ŒํŠธ๋กœ ๋ถ„๋ฆฌ๋œ ํŒŒ์ผ์€ PascalCase์œผ๋กœ ์ž‘์„ฑํ•ฉ๋‹ˆ๋‹ค.
    
    ๐Ÿซ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์•„๋‹Œ ํŒŒ์ผ, ํ•จ์ˆ˜๋ช…, ๋ณ€์ˆ˜๋ช…์€ camelCase๋กœ ์ž‘์„ฑํ•ฉ๋‹ˆ๋‹ค.
    
    ๐Ÿ’„ ๋‹ค๋ฅธ ์Šคํƒ€์ผ ์‹œํŠธ ํŒŒ์ผ(Styled-components)์€, ์Šคํƒ€์ผ ์‹œํŠธ ์ ์šฉํ•  ํŒŒ์ผ๋ช… .style.js๋ฅผ ๋ถ™์—ฌ์ฃผ๊ณ , ์•ž๊ธ€์ž๋Š” ์†Œ๋ฌธ์ž๋กœ ํ•ฉ๋‹ˆ๋‹ค. (ํ™•์žฅ์ž๋Š” .js)
    
    ๐Ÿซ ํ•จ์ˆ˜๋ช…, ๋ณ€์ˆ˜๋ช…์€ camelCase๋กœ ์ž‘์„ฑํ•ฉ๋‹ˆ๋‹ค.
    
    ๐Ÿ’ฌ ๋ฌธ์ž์—ด์„ ์ฒ˜๋ฆฌํ•  ๋•Œ๋Š” ์Œ๋”ฐ์˜ดํ‘œ๋ฅผ ์‚ฌ์šฉํ•˜๋„๋ก ํ•ฉ๋‹ˆ๋‹ค.
    
    ๐Ÿ”š ๋ฌธ์žฅ์ด ์ข…๋ฃŒ๋  ๋•Œ๋Š” ์„ธ๋ฏธ์ฝœ๋ก ์„ ๋ถ™์—ฌ์ค๋‹ˆ๋‹ค.
    
    ๐Ÿ‘† ๊ฐ€๋…์„ฑ์„ ์œ„ํ•ด ํ•œ ์ค„์— ํ•˜๋‚˜์˜ ๋ฌธ์žฅ๋งŒ ์ž‘์„ฑํ•ฉ๋‹ˆ๋‹ค.
    
    ๐Ÿงฎ ์—ฐ์‚ฐ์ž ์‚ฌ์ด์—๋Š” ๊ณต๋ฐฑ์„ ์ถ”๊ฐ€ํ•˜์—ฌ ๊ฐ€๋…์„ฑ์„ ๋†’์ž…๋‹ˆ๋‹ค.
    
    ๐Ÿ“  ์ฝค๋งˆ ๋‹ค์Œ์— ๊ฐ’์ด ์˜ฌ ๊ฒฝ์šฐ ๊ณต๋ฐฑ์„ ์ถ”๊ฐ€ํ•˜์—ฌ ๊ฐ€๋…์„ฑ์„ ๋†’์ž…๋‹ˆ๋‹ค.
    

TOP ๐Ÿ”ผ


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

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

๋…ธ์…˜์„ ์ด์šฉํ•˜์—ฌ ํ•จ๊ป˜ ์˜๊ฒฌ์„ ๋‚˜๋ˆ„๊ณ  ์‹ค์‹œ๊ฐ„์œผ๋กœ ์˜๊ฒฌ์„ ํ…์ŠคํŠธํ™” ์‹œ์ผœ ๋” ํ™œ๋ฐœํ•œ ํšŒ์˜๋ฅผ ์ง„ํ–‰ ์„œ๋กœ์˜ ์˜๊ฒฌ์ด ๋ฌปํžˆ์ง€ ์•Š๋„๋ก ๊ฐ ํŒ€์›์˜ ์˜๊ฒฌ์„ ์ง‘์ค‘ํ•ด์„œ ๋“ค์—ˆ๊ณ  ํŒ€์› ๋ชจ๋‘๊ฐ€ ์ดํ•ดํ–ˆ๋Š”์ง€ ํ•ญ์ƒ ๋ฌผ์–ด๋ด„ 1์ฐจ๊ฐœ๋ฐœ, 2์ฐจ๊ฐœ๋ฐœ์„ ๋‚˜๋ˆ„์–ด ์ง„ํ–‰ํ•˜์˜€๋Š”๋ฐ ๊ฐ ๊ฐœ๋ฐœ๋‹จ๊ณ„์—์„œ ๋๋‚ด์ง€ ๋ชปํ•œ ํŒ€์›์ด ์žˆ๋‹ค๋ฉด ๋ชจ๋‘ ํ•จ๊ป˜ ๋ชจ์—ฌ ๋„์™€์คŒ


๐Ÿ’ฌ ๋””์Šค์ฝ”๋“œ ๋ฐ ๋…ธ์…˜ํ™œ์šฉ

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

image


๐Ÿ’ก ํŒ€ ๊ทœ์น™

  1. ์ฝ”๋“œ ๋ฆฌ๋ทฐ๋ฅผ ํ†ตํ•ด ํ•จ๊ป˜ ์„ฑ์žฅํ•ด๋‚˜๊ฐ€๊ธฐโค๏ธ
  2. ํ”„๋กœ์ ํŠธ ๋๋‚  ๋•Œ๊นŒ์ง€ ๊ธ์ •์ ์ธ ์ƒ๊ฐ๋งŒ ํ•˜๊ธฐโค๏ธ
  3. ์ฝ”๋“œ ์ปจ๋ฒค์…˜์— ๋งž์ถฐ ์ž‘์„ฑํ•˜๊ธฐโค๏ธ
  4. ๋ฌธ์ œ๊ฐ€ ์ƒ๊ธฐ๋ฉด ํ˜ผ์ž ๋™๋™ ์•“์ง€๋ง๊ณ  ๊ผญ ํŒ€์›๋“ค๊ณผ ์ƒ์˜ํ•˜๊ธฐโค๏ธ
  5. ํšŒ์˜์— ์ฐธ์„ํ•˜์ง€ ๋ชปํ•˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ์ƒ๊ธฐ๋ฉด ์‚ฌ์ „์— ์–˜๊ธฐํ•˜๊ธฐโค๏ธ
  6. ์ €ํฌ ์นœํ•ด์ ธ์š”โค๏ธ
  7. ์ƒ๊ฐ๋‚˜๋Š” ์•„์ด๋””์–ด๊ฐ€ ์žˆ์œผ๋ฉด ๋ฐ”๋กœ๋ฐ”๋กœ ์ด์•ผ๊ธฐํ•˜๊ธฐโค๏ธ
  8. ์งˆ๋ฌธํ•˜๋ฉด ์นœ์ ˆํ•˜๊ฒŒ ๋Œ€๋‹ตํ•ด์ฃผ๊ธฐโค๏ธ
  9. ์ฃผ๊ฐ„ ๋งˆ๋ฌด๋ฆฌํšŒ์˜ ๋•Œ ํž˜๋“ค์—ˆ๋˜ ์ , ๊ณ ๋ฏผ ๋‚˜๋ˆ„๋Š” ์‹œ๊ฐ„ ๊ฐ€์ ธ์š” !โค๏ธ
  10. ํ”„๋กœ์ ํŠธ ๊ด€๋ จ ๊ณต์ง€์‚ฌํ•ญ ์ž˜ ํ™•์ธํ•˜๊ธฐโค๏ธ
  11. ๊ณต์ง€์‚ฌํ•ญ์ด ์žˆ์œผ๋ฉด ์ด๋ชจ์ง€ ๋‚จ๊ฒจ์ฃผ๊ธฐ

ํŒ€๊ทœ์น™์„ ์ •ํ•จ์œผ๋กœ ์†Œ์†๊ฐ ๋ฐ ํŒ€ ์ •์ฒด์„ฑ์„ ๊ฐ•ํ™”ํ–ˆ์Šต๋‹ˆ๋‹ค.

โœจ ์ด์Šˆ ๊ด€๋ฆฌ ํ”„๋กœ์„ธ์Šค

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

  • ์•„๋ฌด๋ฆฌ ์ž‘์€ ์ž‘์—…์ด๋ผ๋„ ์ˆ˜์›”ํ•œ ์ด์Šˆ ์ถ”์ ์„ ์œ„ํ•ด ์ด์Šˆ ๋ฐ˜๋“œ์‹œ ๋“ฑ๋ก ํ›„ ์ž‘์—… ์ง„ํ–‰ (์ž‘์—… ํ•˜๋‚˜๋‹น ์ด์Šˆ ํ•˜๋‚˜) image

  • ์ปจ๋ฒค์…˜ ํ†ต์ผ์„ ์œ„ํ•ด ์ด์Šˆ ํ…œํ”Œ๋ฆฟ ์‚ฌ์šฉ

๐Ÿงš ์ด์Šˆ ํ•ด๊ฒฐ ํ›„ Pull Request ์ƒ์„ฑ

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

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

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

image

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


TOP ๐Ÿ”ผ


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


TOP ๐Ÿ”ผ


9.๐Ÿ“ƒ ํŽ˜์ด์ง€ ์บก์ณ ( ์ œ๋ชฉ ํด๋ฆญ ์‹œ ํ•ด๋‹น ๊ธฐ๋Šฅ ์ƒ์„ธ ์„ค๋ช…์œผ๋กœ ์ด๋™๋ฉ๋‹ˆ๋‹ค. )

1) ํ™ˆ

๐Ÿ”—์‹œ์ž‘ ํ™”๋ฉด ๐Ÿ”—ํšŒ์›๊ฐ€์ž… ํŽ˜์ด์ง€ ๐Ÿ”—๋กœ๊ทธ์ธ ํŽ˜์ด์ง€
splash ํšŒ์›๊ฐ€์ž… ๋กœ๊ทธ์ธ
๐Ÿ”—ํ”ผ๋“œ ํŽ˜์ด์ง€ ๐Ÿ”—๊ฒ€์ƒ‰ ํŽ˜์ด์ง€ ๐Ÿ”—404 ํŽ˜์ด์ง€

2) ์ฑ„ํŒ…

๐Ÿ”—์ฑ„ํŒ… ๋ชฉ๋ก ํŽ˜์ด์ง€

3) ๊ฒŒ์‹œ๊ธ€

๐Ÿ”—๊ฒŒ์‹œ๊ธ€ ์ž‘์„ฑ ํŽ˜์ด์ง€ ๐Ÿ”—๊ฒŒ์‹œ๊ธ€ ์ƒ์„ธ ํŽ˜์ด์ง€ ๐Ÿ”—๊ฒŒ์‹œ๊ธ€ ์ˆ˜์ • ํŽ˜์ด์ง€
แ„€แ…ฆแ„‰แ…ตแ„†แ…ฎแ†ฏแ„‰แ…กแ†ผแ„‰แ…ฆ แ„€แ…ฆแ„‰แ…ตแ„†แ…ฎแ†ฏแ„Œแ…กแ†จแ„‰แ…ฅแ†ผ แ„€แ…ฆแ„‰แ…ตแ„†แ…ฎแ†ฏแ„‰แ…ฎแ„Œแ…ฅแ†ผ
๐Ÿ”—๊ฒŒ์‹œ๊ธ€ ์‚ญ์ œ ๐Ÿ”—๋Œ“๊ธ€ ๊ธฐ๋Šฅ

4) ํ”„๋กœํ•„

๐Ÿ”—๋งˆ์ด ํ”„๋กœํ•„ ํŽ˜์ด์ง€ ๐Ÿ”—ํ”„๋กœํ•„ ์ˆ˜์ • ํŽ˜์ด์ง€ ๐Ÿ”—ํŒ”๋กœ์›Œ/ํŒ”๋กœ์ž‰ ํŽ˜์ด์ง€

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

๐Ÿ”—์ƒํ’ˆ ๋“ฑ๋ก ํŽ˜์ด์ง€ ๐Ÿ”—์ƒํ’ˆ ์ˆ˜์ • ํŽ˜์ด์ง€ ๐Ÿ”—์ƒํ’ˆ ์‚ญ์ œ ํŽ˜์ด์ง€
์ƒํ’ˆ ๋“ฑ๋ก ์ƒํ’ˆ ์ˆ˜์ • ์ƒํ’ˆ ์‚ญ์ œ
๐Ÿ”—์ƒํ’ˆ ์ƒ์„ธํŽ˜์ด์ง€

6) ์บ”๋ฒ„์Šค

๐Ÿ”—์บ”๋ฒ„์Šค

TOP ๐Ÿ”ผ


10.๐Ÿ’ป ์ฐจ๋ณ„ํ™” ์ฝ”๋“œ ์„ค๋ช…

1 ) CustomAxios

  • CustomAxios : axios๋ฅผ ์ปค์Šคํ…€ ํ•˜์—ฌ ๋ฐ˜๋ณต๋˜์–ด ๋“ค์–ด๊ฐ€๋Š” ํ—ค๋” ๊ฐ’๊ณผ baseUrl๋ฅผ ์„ค์ •ํ•˜์—ฌ axios ์‚ฌ์šฉ ์‹œ ํ—ค๋”๊ฐ’๊ณผ baseUrl๋ฅผ ์ƒ๋žตํ•˜๋„๋ก ํ•˜์˜€์Šต๋‹ˆ๋‹ค.
  • ์ด๋ฅผ ํ†ตํ•ด ์ฝ”๋“œ๋ฅผ ๋‹จ์ถ• ์‹œํ‚ฌ์ˆ˜ ์žˆ์—ˆ๊ณ , ํŽธ๋ฆฌํ•˜๊ฒŒ axios๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.
import axios from "axios";

export const customAxios = axios.create();

customAxios.interceptors.request.use(
  (config) => {
    const accessToken = localStorage.getItem("accessToken") || "";
    config.baseURL = process.env.REACT_APP_BASE_URL;
    config.headers.Authorization = accessToken ? `Bearer ${accessToken}` : "";

    return config;
  },
  (error) => {
    console.log(error);
    return Promise.reject(error);
  },
);

2 ) loadsh ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ debounce ๊ธฐ๋Šฅ์„ ์ด์šฉํ•œ ๊ฒ€์ƒ‰ ์ตœ์ ํ™”

  • ๊ธฐ์กด ๊ฒ€์ƒ‰์‹œ onChange ์ด๋ฒคํŠธ์—์„œ input์˜ ๋ณ€ํ™”๊ฐ€ ๊ฐ์ง€๋  ๋•Œ ๋งˆ๋‹ค API์š”์ฒญ์ด ๋ฐœ์ƒํ•˜์—ฌ ๋ถˆํ•„์š”ํ•œ API ์š”์ฒญ์ด ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.
  • debunce์„ ํ†ตํ•ด ์„ค์ •ํ•œ ์‹œ๊ฐ„์ด ๊ฒฝ๊ณผํ•œ ์ดํ›„ ์ด๋ฒคํŠธ๊ฐ€ ํ˜ธ์ถœ๋˜์ง€ ์•Š์„ ๋•Œ ์ด๋ฒคํŠธ๋ฅผ ํ•œ ๋ฒˆ๋งŒ ํ˜ธ์ถœํ•˜๊ฒŒ ํ•ด์ฃผ์–ด ๋ถˆํ•„์š”ํ•œ API ํ˜ธ์ถœ์„ ๋ง‰์•„์ค๋‹ˆ๋‹ค.
  • lodash debounce๋Š” ์ฒซ ๋ฒˆ์งธ ์ธ์ž๋กœ ์‹คํ–‰ํ•  ํ•จ์ˆ˜, ๋‘ ๋ฒˆ์งธ ์ธ์ž๋กœ ์‹œ๊ฐ„์„ ๋ฐ›์Šต๋‹ˆ๋‹ค.
// debounceํŒจํ„ด ์ ์šฉํ•œ ์œ ์ € ๊ฒ€์ƒ‰ ํ•จ์ˆ˜
 const handleSearch = useCallback(
    debounce(async (value) => {
      try {
        const response = await customAxios.get(
          `/user/searchuser/?keyword=${value}`,
        );
        setUserList(response.data);
      } catch (error) {
        console.error(error);
      }
    }, 500), // 500ms ๋™์•ˆ ์ž…๋ ฅ์ด ์—†๋‹ค๋ฉด ํ•จ์ˆ˜์‹คํ–‰
    [],
  );
  • ๊ตฌํ˜„ ํ™”๋ฉด

    • debounce ์ ์šฉ ์ „

    ๋””๋ฐ”์šด์‹ฑ์ ์šฉ์ „

    • debounce ์ ์šฉ ํ›„

    ๋””๋ฐ”์šด์‹ฑ์ ์šฉํ›„


3 ) img Validation

  • imgValidation ํ•จ์ˆ˜๋ฅผ ๋งŒ๋“ค์–ด์„œ ์ด๋ฏธ์ง€ ์‚ฌ์šฉ ํŽ˜์ด์ง€์— ๊ณตํ†ต์œผ๋กœ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•˜๋„๋ก ์ ์šฉํ•˜์˜€์Šต๋‹ˆ๋‹ค.
  • imgValidation์„ ํ•จ์ˆ˜๋กœ ๋งŒ๋“ค์–ด์„œ ์ฝ”๋“œ ์ค‘๋ณต์‚ฌ์šฉ์„ ํ”ผํ•˜๊ณ  imgValidation ํ•˜๋‚˜๋กœ ํ†ต์ผํ•˜์˜€์Šต๋‹ˆ๋‹ค.
  • ์ด๋ฏธ์ง€ ํŒŒ์ผ์ด ์—†๊ฑฐ๋‚˜ API์—์„œ ์ œ๊ณตํ•˜๋Š” ์ด๋ฏธ์ง€ ํ˜•์‹์ด ์•„๋‹ˆ๊ฑฐ๋‚˜ ํฌ๊ธฐ๊ฐ€ ์ดˆ๊ณผํ•œ๋‹ค๋ฉด ์ด๋ฏธ์ง€๋ฅผ ์˜ฌ๋ฆฌ์ง€ ๋ชปํ•˜๋„๋ก ์ œํ•œํ•˜๊ณ , ๊ฒฝ๊ณ ์ฐฝ์ด ์ถœ๋ ฅ๋˜๋„๋ก ํ•˜์˜€์Šต๋‹ˆ๋‹ค.
export const imgValidation = (file) => {
  const reg = /(.*?)\.(jpg|jpeg|png|gif|bmp|tif|heic)$/;
  // ํŒŒ์ผ ํ™•์ธ
  if (!file) {
    return false;
  }
  // ํŒŒ์ผ ์‚ฌ์ด์ฆˆ ํ™•์ธ
  if (file.size > 1024 * 1024 * 10) {
    alert("์ด๋ฏธ์ง€ ํŒŒ์ผ์˜ ํฌ๊ธฐ๋ฅผ ์ดˆ๊ณผํ•˜์˜€์Šต๋‹ˆ๋‹ค.(์ตœ๋Œ€ 10MB)");
    return false;
  }
  // ์ด๋ฏธ์ง€ ์ง€์› ํ˜•์‹ ํ™•์ธ
  if (!reg.test(file.name)) {
    alert(
      "์ด๋ฏธ์ง€ ํ˜•์‹์„ ํ™•์ธํ•ด ์ฃผ์„ธ์š”!\n(์ง€์›ํ˜•์‹ : .jpg,.gif, .png,.jpeg, .bmp,.tif, *.heic)",
    );
    return false;
  }
  // ๋ชจ๋‘ ๋งŒ์กฑ ํ•œ๋‹ค๋ฉด true ๋ฐ˜ํ™˜
  return true;
};
  • ๊ตฌํ˜„ ํ™”๋ฉด
    • ํ”„๋กœํ•„ ์ด๋ฏธ์ง€ ๋ณ€๊ฒฝ์— imgValidation ์ ์šฉ

imgValidation


4 ) ๋ฌดํ•œ์Šคํฌ๋กค

  • ๋ฌดํ•œ์Šคํฌ๋กค์„ ์ด์šฉํ•˜์—ฌ ๋ฐ์ดํ„ฐ๋ฅผ ์ผ๋ถ€๋งŒ ๊ฐ€์ ธ์™€ ์„œ๋ฒ„์˜ ๋ถ€๋‹ด์„ ์ค„์ด๊ณ  ๋กœ๋”ฉ์†๋„๋ฅผ ๊ฐœ์„  ํ•˜์˜€์Šต๋‹ˆ๋‹ค.
  • react-intersection-observer ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์ด์šฉํ•˜์—ฌ ๋ฌดํ•œ์Šคํฌ๋กค์„ ๊ตฌํ˜„ํ•˜์˜€์Šต๋‹ˆ๋‹ค.
  • react-intersection-observer ๋ผ์ด๋ธŒ๋Ÿฌ์ด์˜ useView()์˜ ref๊ฐ’์„ ๊ด€์ฐฐ์š”์†Œ ref๊ฐ’์— ๋„ฃ์œผ๋ฉด ๊ด€์ฐฐ์š”์†Œ๋ฅผ ์ง€์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ๋งŒ์•ฝ ๊ด€์ฐฐ์š”์†Œ๊ฐ€ ํ™”๋ฉด ์ถœ๋ ฅ๋˜๋ฉด inView true๋กœ ํ™”๋ฉด์—์„œ ์‚ฌ๋ผ์ง„๋‹ค๋ฉด false๋กœ ๋ณ€๊ฒฝ๋˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.
  • hasMore๋ฅผ ํ†ตํ•ด ๋‹ค์Œ ๋ฐ์ดํ„ฐ๊ฐ€ ์—†๋‹ค๋ฉด api ์š”์ฒญ์„ ์ผ์–ด๋‚˜์ง€ ์•Š๊ฒŒ ์กฐ๊ฑด์„ ๊ฑธ์–ด ์ฃผ์—ˆ์Šต๋‹ˆ๋‹ค.
  • hasMore๋Š” ํ˜„์žฌ API์—์„œ ๋ฐ›์•„์˜จ post์˜ length์™€ limt๊ฐ€ ๊ฐ™์€์ง€ ๋น„๊ตํ•˜์—ฌ ๋‹ค์Œ ๋ฐ์ดํ„ฐ๊ฐ€ ์žˆ๋Š”์ง€ ํŒ๋‹จํ•ด์ค๋‹ˆ๋‹ค.
  • API ์š”์ฒญ์„ ๋ณด๋‚ผ ๋•Œ ๋งˆ๋‹ค skip ๊ฐ’์„ limit ๊ฐ’๋งŒ ๋งŒํผ ์ฆ๊ฐ€ ์‹œ์ผœ์ฃผ์–ด ๋‹ค์Œ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ›์•„์˜ฌ์ˆ˜ ์žˆ๋„๋ก ํ•˜์˜€์Šต๋‹ˆ๋‹ค.
export default function ProfilePost({
  onClickButton,
  settingPostModalProps,
  closeModal,
  userData,
  isFeed,
}) {
  const [postData, setPostData] = useState([]);
  const [isNonePostData, setIsNonePostData] = useState(false);
  const [isGallery, setIsGallery] = useState(false);
  const [isLoading, setIsLoading] = useState(true);
  const [ref, inVeiw] = useInView();
  const limit = 5;
  const [skip, setSkip] = useState(0);
  const [hasMore, setHasMore] = useState(true);
  const navigate = useNavigate();

  // ๊ฒŒ์‹œ๋ฌผ ์ •๋ณด๋ฅผ ๋ฐ›์•„์˜ด
  const fetchPostData = async () => {
    try {
      const response = await customAxios(
        isFeed
          ? `post/feed?limit=${limit}&skip=${skip}`
          : `post/${userData.accountname}/userpost?limit=${limit}&skip=${skip}`,
      );
      const data = isFeed ? response.data.posts : response.data.post;
      setPostData((prev) => [...prev, ...data]);
      setHasMore(data.length === limit);
      setSkip((prev) => prev + limit);
      setIsLoading(false);
      if (data.length === 0 && skip === 0) {
        setIsNonePostData(true);
      } else {
        setIsNonePostData(false);
      }
    } catch (error) {
      console.log(error);
    }
  };

  useEffect(() => {
    if (skip === 0 && !inVeiw) {
      fetchPostData();
    }
    if (hasMore && inVeiw) {
      fetchPostData();
    }
  }, [inVeiw]);

  return (
    // isFeed๋ฅผ ํ†ตํ•ด profile ํŽ˜์ด์ง€์—์„œ ์ถœ๋ ฅ๋  ์š”์†Œ์™€ feed ํŽ˜์ด์ง€์—์„œ ์ถœ๋ ฅ๋  ์š”์†Œ๋ฅผ ๊ตฌ๋ถ„
    <ProfilePostWrapper>
           (์ค‘๋žต)...
            <ProfilePostUl>
              {postData.map((post) => (
                <ProfilePostList
                  key={post.id}
                  onClickButton={onClickButton}
                  settingPostModalProps={settingPostModalProps}
                  closeModal={closeModal}
                  reFetchPostData={fetchPostData}
                  post={post}
                  setPostData={setPostData}
                  isFeed={isFeed}
                  userData={userData}
                />
              ))}
              <div ref={ref}></div>
            </ProfilePostUl>
          )}
        </>
      )}
    </ProfilePostWrapper>
  );
}
  • ๊ตฌํ˜„ ํ™”๋ฉด

๋ฌดํ•œ์Šคํฌ๋กค


TOP ๐Ÿ”ผ


5 ) ์ด๋ฏธ์ง€ lazy-loading ์ ์šฉ ๋ฐ ์ ์ง„์  ๋กœ๋”ฉ ๊ธฐ๋ฒ•์„ ํ†ตํ•œ ์ด๋ฏธ์ง€ ์ตœ์ ํ™”

  • ์ ์ง„์  ๋กœ๋”ฉ ๊ธฐ๋ฒ•๋ฅผ ํ†ตํ•ด ์ด๋ฏธ์ง€๊ฐ€ ๋กœ๋”ฉ๋  ๋•Œ ์›๋ณธ ์ด๋ฏธ์ง€ ๋Œ€์‹  ์ €ํ™”์งˆ์˜ ์ด๋ฏธ์ง€๋ฅผ ๋ณด์—ฌ์คŒ์œผ๋กœ์จ UX๋ฅผ ํ–ฅ์ƒ ์‹œ์ผฐ์Šต๋‹ˆ๋‹ค.
  • react-intersection-observer ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์ด์šฉํ•˜์—ฌ lazy-loading๋ฅผ ๊ตฌํ˜„ํ•˜์˜€์Šต๋‹ˆ๋‹ค.
  • ์ด๋ฅผ ํ†ตํ•ด ์ด๋ฏธ์ง€๊ฐ€ ํ™”๋ฉด์—์„œ ๋‚˜ํƒ€๋‚  ๋•Œ ์ด๋ฏธ์ง€๋ฅผ ๋ถˆ๋Ÿฌ์˜ฌ ์ˆ˜ ์žˆ๋„๋ก ์„ค์ •ํ•˜์—ฌ ๋กœ๋”ฉ์‹œ๊ฐ„์„ ๋‹จ์ถ• ์‹œํ‚ฌ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ์ด ๋‘ ๊ฐ€์ง€ ๊ธฐ๋ฒ•์„ ์ด๋ฏธ์ง€์— ์ ์šฉํ•˜๊ธฐ ์œ„ํ•ด ProgressiveImg ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋งŒ๋“ค๊ณ , ์ด๋ฏธ์ง€์— ์ ์šฉ์‹œ์ผœ ์ฃผ์—ˆ์Šต๋‹ˆ๋‹ค.
  • ProgressvieImg Props
    • src : ์›๋ณธ ์ด๋ฏธ์ง€์˜ url ์ž…๋‹ˆ๋‹ค.
    • ...props : ๊ทธ ์™ธ props๋ฅผ ๋ชจ๋‘ ๋ฐ›์•„์˜ค๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉ ํ•˜์˜€์Šต๋‹ˆ๋‹ค.
  • ์ด๋ฏธ์ง€ lazy-loading ์ ์šฉ ํ›„ ์ดˆ๊ธฐ ๋กœ๋”ฉ ์†๋„ 1.9์ดˆ์—์„œ 1.5์ดˆ๋กœ 0.4์ดˆ ๊ฐ์†Œ ๋ฐ ์ด๋ฏธ์ง€ ๋ฆฌ์†Œ์Šค 4.5MB ์—์„œ 2.6MB ๋กœ 1.9MB(์•ฝ 42%) ๊ฐ์†Œํ•˜์˜€์Šต๋‹ˆ๋‹ค.
import React, {useEffect, useState } from "react";
import { Img } from "./progressiveImg.styles";
import { useInView } from "react-intersection-observer";
import noImg from "../../../img/no-image.svg";
import noImgWebp from "../../../img/webp/no-image.webp";
import { resolveWebp } from "../../../library/checkWebpSupport";
import placeholderImg from "../../../img/placeholderImg.svg";
import placeholderImgWebp from "../../../img/webp/placeholderImg.webp";

// ProgressvieImg ์ปดํฌ๋„ŒํŠธ
export default function ProgressiveImg({ src, ...props }) {
  const placeholderSrc = resolveWebp(placeholderImgWebp, placeholderImg);
  // ์ด๋ฏธ์ง€ src๋ฅผ ๊ด€๋ฆฌ
  const [imgSrc, setImgSrc] = useState(placeholderSrc || src);
  // ํ˜„์žฌ ๋กœ๋”ฉ์ด ์ƒํƒœ
  const [isLoading, setIsLoading] = useState(true);
  const { ref, inView } = useInView();
  useEffect(() => {
    // ์ด๋ฏธ์ง€๊ฐ€ ํ™”๋ฉด์—์„œ ๋ณด์ด๊ณ , imgSrc๊ฐ€ placholder์ด๋ฏธ์ง€ ์ผ๋•Œ ์ด๋ฏธ์ง€๋ฅผ ๋ฐ›์•„์˜ด
    if (inView && imgSrc === placeholderSrc) {
      const img = new Image();
      img.src = src;
      img.onload = () => {
        setImgSrc(src);
        setIsLoading(false);
      };
      img.onerror = () => {
        setIsLoading(false);
        setImgSrc(resolveWebp(noImgWebp, noImg));
      };
    }
  }, [src, inView]);

  return (
    <Img
      {...{ src: imgSrc, ...props }}
      // ๋กœ๋”ฉ ์ƒํƒœ์ผ ๋•Œ blurํšจ๊ณผ๋ฅผ ์ฃผ๊ธฐ์œ„ํ•ด ์‚ฌ์šฉ
      className={isLoading ? "loading" : "loaded"}
      ref={ref}
    />
  );
}
  • ๊ตฌํ˜„ํ™”๋ฉด
    • ์ด๋ฏธ์ง€ lazy-loading ๋ฐ ์ ์ง„์  ๋กœ๋”ฉ ๊ธฐ๋ฒ• ์ ์šฉ ์ „

      lazy-loading ์ ์šฉ์ „

    • ์ด๋ฏธ์ง€ lazy-loading ๋ฐ ์ ์ง„์  ๋กœ๋”ฉ ๊ธฐ๋ฒ•์ ์šฉ ํ›„

      lazy-loading ์ ์šฉํ›„


TOP ๐Ÿ”ผ


6 ) ์ตœ์‹  ์ด๋ฏธ์ง€ ํ˜•์‹ Webp ์ ์šฉ

  • WebP ์ด๋ฏธ์ง€๋Š” JPEG๋‚˜ PNG์— ๋น„ํ•ด ์••์ถ•๋ฅ ์ด ๋†’๊ณ , ๋” ์ž‘์€ ํŒŒ์ผ ํฌ๊ธฐ๋ฅผ ๊ฐ€์ง€๋ฉฐ, ๋†’์€ ํ’ˆ์งˆ์„ ์ œ๊ณตํ•˜๋Š” ์ด๋ฏธ์ง€ ํ˜•์‹์ž…๋‹ˆ๋‹ค.

  • Webp ์ด๋ฏธ์ง€ ํ˜•์‹์€ ๊ตฌ ๋ธŒ๋ผ์šฐ์ €๋Š” ์ง€์›ํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— ์ ์ง„์  ํ–ฅ์ƒ ๊ธฐ๋ฒ•์„ ์ด์šฉํ•˜์—ฌ ๋‹ค๋ฅด๊ฒŒ ์ฒ˜๋ฆฌํ•ด ์ฃผ์—ˆ์Šต๋‹ˆ๋‹ค.

  • Webp ์ด๋ฏธ์ง€๊ฐ€ ์ง€์›์ด ๋œ๋‹ค๋ฉด body ํƒœ๊ทธ์— webp๋ผ๋Š” className๋ฅผ ์ถ”๊ฐ€ํ•ด์ฃผ๊ณ , ์ง€์›๋˜์ง€ ์•Š๋Š”๋‹ค๋ฉด no-webp๋ผ๋Š” className์„ ์ถ”๊ฐ€ํ•ด์ฃผ์—ˆ์Šต๋‹ˆ๋‹ค.

  • body className๋ฅผ ํ†ตํ•ด ์ด๋ฏธ์ง€ ํ˜•์‹์ด ๋‹ค๋ฅด๊ฒŒ ์ ์šฉ๋˜๋„๋ก ์ฒ˜๋ฆฌํ•˜์˜€์Šต๋‹ˆ๋‹ค.

  • ๊ตฌ ๋ธŒ๋ผ์šฐ์ €์—์„œ๋Š” svg ์ด๋ฏธ์ง€ ํ˜•์‹์ด ์ ์šฉ๋˜๋„๋ก ์ฒ˜๋ฆฌํ•˜์˜€์Šต๋‹ˆ๋‹ค.

  • Webp๊ฐ€ ์ง€์›๋˜๋Š” ๋ธŒ๋ผ์šฐ์ €์—์„œ๋Š” Webp ์ด๋ฏธ์ง€๊ฐ€ ์ ์šฉ๋˜๋„๋ก ์ฒ˜๋ฆฌํ•˜์˜€์Šต๋‹ˆ๋‹ค.

  • detectWebpSupport, resolveWebp ํ•จ์ˆ˜๋ฅผ ๋งŒ๋“ค์–ด ์ด๋ฅผ ์ ์šฉ์‹œ์ผœ ์ฃผ์—ˆ์Šต๋‹ˆ๋‹ค.

  • detectWebpSupport

    • webpdata์— 1x1 ํ”ฝ์…€ ํฌ๊ธฐ์˜ WebP ํ˜•์‹์˜ ์ด๋ฏธ์ง€ ๋ฐ์ดํ„ฐ๋ฅผ base64๋กœ ์ธ์ฝ”๋”ฉํ•œ ๋ฌธ์ž์—ด์„ ํ• ๋‹นํ•ฉ๋‹ˆ๋‹ค.
    • ์ด๋ฏธ์ง€ ๋กœ๋”ฉ์ด ์„ฑ๊ณต์ ์œผ๋กœ ์™„๋ฃŒ๋˜๊ฑฐ๋‚˜ ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ–ˆ์„ ๋•Œ callback ํ•จ์ˆ˜๊ฐ€ ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค.
    • webp ์ด๋ฏธ์ง€๊ฐ€ ๋กœ๋”ฉ ๋˜๊ณ , webp์ด๋ฏธ์ง€ ์ง€์›์—ฌ๋ถ€ ํ™•์ธ์„ ๊ธฐ๋‹ค๋ฆฌ๊ธฐ ์œ„ํ•ด Promise๋ฅผ ์ด์šฉํ•ด ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ๋ฅผ ํ•ด์ฃผ์—ˆ์Šต๋‹ˆ๋‹ค.
    • image.src์— webpdata๋ฅผ ํ• ๋‹นํ•˜์—ฌ, ์ƒ์„ฑํ•œ ๋นˆ ์ด๋ฏธ์ง€ ๊ฐ์ฒด๊ฐ€ ํ•ด๋‹น WebP ์ด๋ฏธ์ง€๋ฅผ ๋กœ๋”ฉํ•˜๋„๋ก ํ•ฉ๋‹ˆ๋‹ค.
    • callback ํ•จ์ˆ˜์—์„œ๋Š” event.type์ด "load"์ธ ๊ฒฝ์šฐ์™€ ์ด๋ฏธ์ง€์˜ ๋„ˆ๋น„(image.width)๊ฐ€ 1 ํ”ฝ์…€์ธ ๊ฒฝ์šฐ๋ฅผ ๊ฒ€์‚ฌํ•˜์—ฌ ๋ธŒ๋ผ์šฐ์ €๊ฐ€ WebP ์ด๋ฏธ์ง€๋ฅผ ์ง€์›ํ•˜๋Š”์ง€ ์—ฌ๋ถ€๋ฅผ ํŒ๋ณ„ํ•ฉ๋‹ˆ๋‹ค.
    • ๋ธŒ๋ผ์šฐ์ €๊ฐ€ WebP ์ด๋ฏธ์ง€๋ฅผ ์ง€์›ํ•˜๋Š” ๊ฒฝ์šฐ document.body ์š”์†Œ์˜ classList์— "webp"๋ฅผ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.
    • ์ง€์›ํ•˜์ง€ ์•Š๋Š” ๋ธŒ๋ผ์šฐ์ €๋ผ๋ฉด document.body ์š”์†Œ์˜ classList์— "no-webp"๋ฅผ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.
  • resolveWebp

    • webpSupported: webp์ง€์› ์œ ๋ฌด, img : Webp ์ด๋ฏธ์ง€ ๊ฒฝ๋กœ, fallbackExt : Webp ์ด๋ฏธ์ง€ ๋Œ€์‹  ์‚ฌ์šฉํ•  ์ด๋ฏธ์ง€ ๊ฒฝ๋กœ
    • ext์— ์ด๋ฏธ์ง€ ํ˜•์‹์„ ์ €์žฅํ•ฉ๋‹ˆ๋‹ค.
    • webpSupported๊ฐ€ false์ธ ๊ฒฝ์šฐ, ext์ด webp์ธ ๊ฒฝ์šฐ์— webp์ด๋ฏธ์ง€ ๊ฒฝ๋กœ ๋Œ€์‹  webp ๋Œ€์‹  ์‚ฌ์šฉํ•  ์ด๋ฏธ์ง€ ๊ฒฝ๋กœ๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.
  • Webp ์ด๋ฏธ์ง€ ์ ์šฉ์œผ๋กœ ๋กœ์ปฌ ์ด๋ฏธ์ง€ ํŒŒ์ผ ๋ฆฌ์†Œ์Šค๋ฅผ 350KB์—์„œ 37KB๋กœ 313KB ์ค„์˜€์Šต๋‹ˆ๋‹ค.

export async function detectWebpSupport() {
  // ์ด๋ฏธ์ง€๊ฐ€ webp ์ง€์›์œ ๋ฌด๋ฅผ ํŒŒ์•…ํ•˜๊ณ  ๋ Œ๋”๋ง ๋  ์ˆ˜ ์žˆ๋„๋ก ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ
  return new Promise((resolve) => {
    const image = new Image();
    // 1px x 1px WebP ์ด๋ฏธ์ง€
    const webpdata =
      "data:image/webp;base64,UklGRiQAAABXRUJQVlA4IBgAAAAwAQCdASoBAAEAAwA0JaQAA3AA/vuUAAA=";

    const callback = (event) => {
      // event.type์ด "load"์ธ ๊ฒฝ์šฐ์™€ ์ด๋ฏธ์ง€์˜ ๋„ˆ๋น„(image.width)๊ฐ€ 1 ํ”ฝ์…€์ธ ๊ฒฝ์šฐ๋ฅผ ๊ฒ€์‚ฌํ•˜์—ฌ ๋ธŒ๋ผ์šฐ์ €๊ฐ€ WebP ์ด๋ฏธ์ง€๋ฅผ ์ง€์›ํ•˜๋Š”์ง€ ์—ฌ๋ถ€๋ฅผ ํŒ๋ณ„
      const result = event?.type === "load" && image.width === 1;
      if (result) {
        resolve(true); // WebP ์ง€์›๋จ
      } else {
        resolve(false); // WebP ์ง€์›๋˜์ง€ ์•Š์Œ
      }
    };

    image.onerror = callback;
    image.onload = callback;
    image.src = webpdata;
  });
}
// webpSupported: webp ์ง€์› ์œ ๋ฌด, img: webp ์ด๋ฏธ์ง€ ๊ฒฝ๋กœ, fallbackExt: webp ์ด๋ฏธ์ง€ ๋Œ€์ฒด ์ด๋ฏธ์ง€ ํ˜•์‹
export const resolveWebp = (img, fallbackImg) => {
  const webpSupported = document.body.classList.contains("webp");
  // ์ด๋ฏธ์ง€ ํฌ๋งท
  const ext = img.split(".").pop();
  // webpSupported false, ext๊ฐ€ webp์ธ ๊ฒฝ์šฐ
  if (!webpSupported && ext === "webp") {
    return fallbackImg
  }
  return img;
};

TOP ๐Ÿ”ผ


7 ) imgCompression ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์ด์šฉํ•œ ์ด๋ฏธ์ง€ ์••์ถ•

  • ์„œ๋ฒ„์— ์ด๋ฏธ์ง€๋ฅผ ์ „์†กํ•  ์‹œ ํ•„์š”ํ•œ ์ด๋ฏธ์ง€ ๋งŒํผ๋งŒ ์ตœ์†Œ๋กœ ์••์ถ•ํ•˜์—ฌ ์ด๋ฏธ์ง€ ๋ฆฌ์†Œ์Šค ๋‚ญ๋น„๋ฅผ ์ค„์ผ ์ˆ˜ ์žˆ๋„๋ก ํ•˜์˜€์Šต๋‹ˆ๋‹ค.
  • imgCompression ํ•จ์ˆ˜๋ฅผ ๋งŒ๋“ค์–ด ์ด๋ฅผ ์ ์šฉ ํ•˜์˜€์Šต๋‹ˆ๋‹ค.
import imageCompression from "browser-image-compression";

export const uploadImgCompression = async (file) => {
  const options = {
    maxSizeMB: 10,
    maxWidthOrHeight: 304,
    useWebWorker:true,
  }
  const compressedFileBlob = await imageCompression(file, options);
  const preview = await imageCompression.getDataUrlFromFile(compressedFileBlob);
  return {compressedFileBlob, preview}
}

export const profileImgCompression = async (file) => {
  const options = {
    maxSizeMB: 10,
    maxWidthOrHeight: 220,
    useWebWorker:true,
  }
  const compressedFileBlob = await imageCompression(file, options);
  const preview = await imageCompression.getDataUrlFromFile(compressedFileBlob);
  return {compressedFileBlob, preview}
}
  • ๊ตฌํ˜„ ํ™”๋ฉด

imgCompression

  • ์ด๋ฏธ์ง€ ์••์ถ• ์ „

    ์ด๋ฏธ์ง€ ํฌ๊ธฐ : 412MB

  • ์ด๋ฏธ์ง€ ์••์ถ• ํ›„

    ์ด๋ฏธ์ง€ ํฌ๊ธฐ : 412MB => 57MB (355MB ๊ฐ์†Œ)


TOP ๐Ÿ”ผ


11.๐Ÿ’ซ ๋Š๋‚€์ 

๊ฐ•์œค์ •

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


๋‚จ์ข…ํƒœ

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


์•ˆ๋‚˜๋ณ„

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


์–‘์„œ์ง„

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


TOP ๐Ÿ”ผ


12.๐Ÿ—‚ ํ”„๋กœ์ ํŠธ ๊ตฌ์กฐ

  • src/components/ : ์„œ๋น„์Šค์—์„œ ์‚ฌ์šฉํ•˜๋Š” ์ปดํฌ๋„ŒํŠธ (๊ณตํ†ต ์ปดํฌ๋„ŒํŠธ, ๊ณตํ†ต ๋ ˆ์ด์•„์›ƒ)
  • src/commons/ : ๊ณตํ†ต์ปดํฌ๋„ŒํŠธ ์ค‘ UI์™€ ๊ด€๋ จ๋œ ํŒŒ์ผ
  • src/context/ : ์ „์—ญ ๋ฐ์ดํ„ฐ๋ฅผ ๊ณต์œ ํ•˜๊ธฐ ์œ„ํ•ด ์ •์˜ํ•œ Context ํŒŒ์ผ
  • src/hooks/ : ์žฌ์‚ฌ์šฉ์„ ์œ„ํ•ด ๋ถ„๋ฆฌํ•œ Custom Hook
  • src/img/ : ์„œ๋น„์Šค์—์„œ ์‚ฌ์šฉํ•˜๋Š” ์—์…‹ ํŒŒ์ผ (ํฐํŠธ, ์•„์ด์ฝ˜, ์ด๋ฏธ์ง€)
  • src/library/ : ์‚ฌ์šฉ์„ ํŽธ๋ฆฌํ•˜๊ฒŒ ํ•˜๊ฑฐ๋‚˜ ์žฌ์‚ฌ์šฉ์„ ์ค„์ด๊ธฐ ์œ„ํ•ด ๋งŒ๋“  ํ•จ์ˆ˜
  • src/pages/ : ์ปดํฌ๋„ŒํŠธ๋ฅผ ์กฐํ•ฉํ•˜์—ฌ ๋งŒ๋“  ํŽ˜์ด์ง€
  • src/routes/ : ํŽ˜์ด์ง€ ๋ผ์šฐํŒ…์„ ์œ„ํ•œ ํŒŒ์ผ
๐Ÿ“ฆsusuMarket
 โ”ฃ ๐Ÿ“‚public
   โ”— ๐Ÿ“œindex.html
 โ”ฃ ๐Ÿ“‚src
   โ”ฃ ๐Ÿ“‚components
   โ”ƒ โ”ฃ ๐Ÿ“‚commons
   โ”ƒ โ”ƒ โ”ฃ ๐Ÿ“‚button
   โ”ƒ โ”ƒ โ”ฃ ๐Ÿ“‚confirmModal
   โ”ƒ โ”ƒ โ”ฃ ๐Ÿ“‚dataInput
   โ”ƒ โ”ƒ โ”ฃ ๐Ÿ“‚dateFormat
   โ”ƒ โ”ƒ โ”ฃ ๐Ÿ“‚errorMessage
   โ”ƒ โ”ƒ โ”ฃ ๐Ÿ“‚menuBar
   โ”ƒ โ”ƒ โ”ฃ ๐Ÿ“‚newTopHeader
   โ”ƒ โ”ƒ โ”ฃ ๐Ÿ“‚postList
   โ”ƒ โ”ƒ โ”ฃ ๐Ÿ“‚postModal
   โ”ƒ โ”ƒ โ”ฃ ๐Ÿ“‚progressiveImg
   โ”ƒ โ”ƒ โ”ฃ ๐Ÿ“‚topButton
   โ”ƒ โ”ƒ โ”ฃ ๐Ÿ“‚userInfo
   โ”ƒ โ”— โ”— ๐Ÿ“‚topHeader
   โ”ฃ ๐Ÿ“‚context
   โ”ฃ ๐Ÿ“‚hook
   โ”ฃ ๐Ÿ“‚img
   โ”ฃ ๐Ÿ“‚library
   โ”ƒ โ”ฃ ๐Ÿ“‚sweetAlert
   โ”ƒ โ”ฃ ๐Ÿ“œcheckWebpSupport.js
   โ”ƒ โ”ฃ ๐Ÿ“œcustomAxios.js
   โ”ƒ โ”ฃ ๐Ÿ“œimgCompression.js
   โ”ƒ โ”— ๐Ÿ“œimgValidation.js
   โ”ฃ ๐Ÿ“‚pages
   โ”ƒ โ”ฃ ๐Ÿ“‚chat
   โ”ƒ โ”ƒ โ”ฃ ๐Ÿ“‚chatList
   โ”ƒ โ”ƒ โ”— ๐Ÿ“‚chatRoom
   โ”ƒ โ”ฃ ๐Ÿ“‚drawing
   โ”ƒ โ”ฃ ๐Ÿ“‚feed
   โ”ƒ โ”ƒ โ”ฃ ๐Ÿ“‚post
   โ”ƒ โ”ƒ โ”ƒ โ”ฃ ๐Ÿ“‚postDetail
   โ”ƒ โ”ƒ โ”ƒ โ”ฃ ๐Ÿ“‚postEdit
   โ”ƒ โ”ƒ โ”ƒ โ”ฃ ๐Ÿ“‚postUpload
   โ”ƒ โ”ƒ โ”ฃ ๐Ÿ“‚product
   โ”ƒ โ”ƒ โ”ƒ โ”ฃ ๐Ÿ“‚productDetail
   โ”ƒ โ”ƒ โ”ƒ โ”ฃ ๐Ÿ“‚productEdit
   โ”ƒ โ”ƒ โ”ƒ โ”— ๐Ÿ“‚productUpload
   โ”ƒ โ”ƒ โ”— ๐Ÿ“‚search
   โ”ƒ โ”ฃ ๐Ÿ“‚login
   โ”ƒ โ”ƒ โ”ฃ ๐Ÿ“‚loginEmail
   โ”ƒ โ”ฃ ๐Ÿ“‚notFound
   โ”ƒ โ”ฃ ๐Ÿ“‚profile
   โ”ƒ โ”ƒ โ”ฃ ๐Ÿ“‚follow
   โ”ƒ โ”ƒ โ”ƒ โ”ฃ ๐Ÿ“‚followers
   โ”ƒ โ”ƒ โ”ƒ โ”— ๐Ÿ“‚following
   โ”ƒ โ”ƒ โ”ฃ ๐Ÿ“‚profileEdit
   โ”ƒ โ”ƒ โ”— ๐Ÿ“‚userProfile
   โ”ƒ โ”ƒ โ”ƒ โ”ฃ ๐Ÿ“‚profileInfo
   โ”ƒ โ”ƒ โ”ƒ โ”— ๐Ÿ“‚profileProduct     
   โ”ƒ โ”ฃ ๐Ÿ“‚signup
   โ”ƒ โ”ƒ โ”ฃ ๐Ÿ“‚profileSetting
   โ”ƒ โ”ƒ โ”— ๐Ÿ“‚userAccount
   โ”ƒ โ”— ๐Ÿ“‚splash
   โ”ฃ ๐Ÿ“‚routes
   โ”ฃ .prettierrc.json 
   โ”ฃ ๐Ÿ“œApp.js
   โ”ฃ ๐Ÿ“œGlobalStyle.js
   โ”— ๐Ÿ“œindex.js

TOP ๐Ÿ”ผ


About

๐ŸŽจ ์ˆ˜์ˆ˜๋งˆ์ผ“ ์˜ˆ์ˆ ์ž‘ํ’ˆ์„ ์‚ฌ๋ž‘ํ•˜๋Š” ์‚ฌ๋žŒ๋“ค์„ ์œ„ํ•œ SNS/์ปค๋ฎค๋‹ˆํ‹ฐ ์„œ๋น„์Šค์ž…๋‹ˆ๋‹ค.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Contributors 4

  •  
  •  
  •  
  •  

Languages