Skip to content

๐Ÿพ ๋ฐ˜๋ ค๋™๋ฌผ ํ†ตํ•ฉ ์ปค๋ฎค๋‹ˆํ‹ฐ ์„œ๋น„์Šค

Notifications You must be signed in to change notification settings

FRONTENDSCHOOL5/final-22-undefined

Folders and files

NameName
Last commit message
Last commit date

Latest commit

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

Repository files navigation

๐Ÿฆด Happy-Paw



๐Ÿพ ํ•ดํ”ผํฌ (Happy-Paw) : ๋ฐ˜๋ ค๋™๋ฌผ ํ†ตํ•ฉ ์ปค๋ฎค๋‹ˆํ‹ฐ ์„œ๋น„์Šค

๋ฐฐํฌ URL ํ…Œ์ŠคํŠธ ID ํ…Œ์ŠคํŠธ PW
https://happy4.netlify.app/ happypaw@gmail.com happypawpw



0. ๋ชฉ์ฐจ

  1. ํ”„๋กœ์ ํŠธ ์†Œ๊ฐœ
  2. ๊ฐœ๋ฐœ ํ™˜๊ฒฝ
  3. ํ˜‘์—… ํ™˜๊ฒฝ
  4. ์—ญํ•  ๋ถ„๋‹ด
  5. ํ”„๋กœ์ ํŠธ ๊ตฌํ˜„
  6. ํ•ต์‹ฌ ์ฝ”๋“œ
  7. ํŠธ๋Ÿฌ๋ธ” ์ŠˆํŒ…



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

  • ๐Ÿฑ ๋ฐ˜๋ ค๋™๋ฌผ์˜ ์ •๋ณด๋ฅผ ๊ณต์œ ํ•˜๋Š” ์ปค๋ฎค๋‹ˆํ‹ฐ๋ฅผ ๊ตฌ์ถ•ํ•ฉ๋‹ˆ๋‹ค.
  • ๐Ÿ›๏ธย ์›ํ•˜๋Š” ๋ฌผํ’ˆ์„ ํŒ๋งคํ•˜๊ฑฐ๋‚˜ ๊ตฌ๋งคํ•˜๋Š” ์„œ๋น„์Šค๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.
  • ๐Ÿงค ์‚ฌ์šฉ์ž๋“ค ๋ผ๋ฆฌ ํŒ”๋กœ์šฐ ๊ธฐ๋Šฅ์„ ํ†ตํ•ด ์„œ๋กœ์˜ ์†Œ์‹์„ ๊ณต์œ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ๐Ÿ–ผ๏ธย ๊ธ€๊ณผ ์‚ฌ์ง„์„ ํ•จ๊ป˜ ์—…๋กœ๋“œํ•˜์—ฌ ๋ฐ˜๋ ค ๋™๋ฌผ๋“ค์˜ ์ผ์ƒ์„ ์ž๋ž‘ํ•˜๊ณ  ๊ณต์œ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ๐Ÿงก ๋‹ค๋ฅธ ์‚ฌ์šฉ์ž๋“ค์˜ ๊ธ€์— ์ข‹์•„์š”๋ฅผ ๋ˆ„๋ฅด๊ณ  ๋Œ“๊ธ€์„ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ๐Ÿ—บ๏ธ ์ง€๋„๊ธฐ๋Šฅ์„ ํ†ตํ•ด ๋‚ด์ฃผ๋ณ€์˜ ๋ฐ˜๋ ค๋™๋ฌผ ์นดํŽ˜, ๋ณ‘์›, ํ˜ธํ…”์„ ์ฐพ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.



2. ๊ฐœ๋ฐœ ํ™˜๊ฒฝ

2-1. ๊ฐœ๋ฐœ๊ธฐ๊ฐ„



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

Front-End Back-End Co-work & etc
์ œ๊ณต๋œ API ์‚ฌ์šฉ




3. ํ˜‘์—… ํ™˜๊ฒฝ

3-1. ํ˜‘์—… ์ปจ๋ฒค์…˜

3-1-1. ํด๋” ๊ตฌ์กฐ

๐Ÿพ HappyPaw
โ”œโ”€ ๐Ÿ“ฆ public
โ”‚  โ”œโ”€ โญ favicon.ico
โ”‚  โ””โ”€ ๐Ÿ“ƒ index.html
โ”œโ”€ ๐Ÿ“ฆ src
โ”‚  โ”œโ”€ ๐Ÿ“‚ api
โ”‚  โ”œโ”€ ๐Ÿ“‚ assets
โ”‚  โ”‚  โ”œโ”€ ๐Ÿ“‚ icon
โ”‚  โ”‚  โ””โ”€ ๐Ÿ“‚ splash
โ”‚  โ”œโ”€ ๐Ÿ“‚ components
โ”‚  โ”‚  โ”œโ”€ ๐Ÿ“‚ common
โ”‚  โ”‚  โ”‚  โ”œโ”€ ๐Ÿ“‚ Button
โ”‚  โ”‚  โ”‚  โ”œโ”€ ๐Ÿ“‚ Carousel
โ”‚  โ”‚  โ”‚  โ”œโ”€ ๐Ÿ“‚ Header
โ”‚  โ”‚  โ”‚  โ”œโ”€ ๐Ÿ“‚ Input
โ”‚  โ”‚  โ”‚  โ”œโ”€ ๐Ÿ“‚ MainLayout
โ”‚  โ”‚  โ”‚  โ”œโ”€ ๐Ÿ“‚ Modal
โ”‚  โ”‚  โ”‚  โ”œโ”€ ๐Ÿ“‚ TabMenu
โ”‚  โ”‚  โ”‚  โ””โ”€ ๐Ÿ“‚ Wrapper
โ”‚  โ”‚  โ”œโ”€ ๐Ÿ“‚ Follow
โ”‚  โ”‚  โ”œโ”€ ๐Ÿ“‚ Post
โ”‚  โ”‚  โ”œโ”€ ๐Ÿ“‚ Product
โ”‚  โ”‚  โ”œโ”€ ๐Ÿ“‚ Profile
โ”‚  โ”‚  โ””โ”€ ๐Ÿ“‚ Skeleton
โ”‚  โ”œโ”€ ๐Ÿ“‚ context
โ”‚  โ”œโ”€ ๐Ÿ“‚ hooks
โ”‚  โ”œโ”€ ๐Ÿ“‚ pages
โ”‚  โ”‚  โ”œโ”€ ๐Ÿ“‚ ChatPage
โ”‚  โ”‚  โ”œโ”€ ๐Ÿ“‚ ErrorPage
โ”‚  โ”‚  โ”œโ”€ ๐Ÿ“‚ FollowListPage
โ”‚  โ”‚  โ”œโ”€ ๐Ÿ“‚ HomePage
โ”‚  โ”‚  โ”œโ”€ ๐Ÿ“‚ JoinPage
โ”‚  โ”‚  โ”œโ”€ ๐Ÿ“‚ LoginPage
โ”‚  โ”‚  โ”œโ”€ ๐Ÿ“‚ MapPage
โ”‚  โ”‚  โ”œโ”€ ๐Ÿ“‚ PostPage
โ”‚  โ”‚  โ”œโ”€ ๐Ÿ“‚ ProductPage
โ”‚  โ”‚  โ”œโ”€ ๐Ÿ“‚ ProfilePage
โ”‚  โ”‚  โ”œโ”€ ๐Ÿ“‚ SearchPage
โ”‚  โ”‚  โ””โ”€ ๐Ÿ“‚ SplashPage
โ”‚  โ”œโ”€ ๐Ÿ“‚ routes
โ”‚  โ”œโ”€ ๐Ÿ“‚ styles
|  โ”œโ”€ ๐Ÿ“œ App.js
|  โ””โ”€ ๐Ÿ“œ index.js


3-1-2. ์ฝ”๋“œ ์ปจ๋ฒค์…˜

  • ํƒ€์ž…์€ ์ข…๋ฅ˜ ์ค‘ย ํ•˜๋‚˜๋งŒ ์„ ํƒํ•˜๋ฉฐ,ย ์˜์–ด ์†Œ๋ฌธ์ž๋กœ ์‹œ์ž‘ํ•œ๋‹ค.
  • ์ฃผ์ œ๋Š” ํ•œ๊ธ€๋กœ ๊ฐ„๋‹จ๋ช…๋ฃŒํ•˜๊ฒŒ ์ž‘์„ฑํ•œ๋‹ค.
  • ์ฃผ์ œ์˜ ๋งˆ์ง€๋ง‰ ๋ฌธ์ž๋กœย .(๋งˆ์นจํ‘œ)๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š”๋‹ค.
  • ์ฃผ์ œ๋Š” '-๋‹ค', '-์Œ'๊ณผ ๊ฐ™์€ ์–ด๋ฏธ๋กœ ๋๋‚ด์ง€ ์•Š๊ณ , ๊ณผ๊ฑฐํ˜•์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š”๋‹ค.
    • ์˜ฌ๋ฐ”๋ฅด์ง€ ์•Š์€ ์˜ˆ )ย feat: ์นด์นด์˜ค ๋กœ๊ทธ์ธ ์—ฐ๋™ ๊ธฐ๋Šฅ์„ ์ถ”๊ฐ€ํ–ˆ๋‹ค, ํ˜น์€ ์ถ”๊ฐ€ํ•จ (#3)
    • ์˜ณ์€ ์˜ˆ )ย feat: ์นด์นด์˜ค ๋กœ๊ทธ์ธ ์—ฐ๋™ ๊ธฐ๋Šฅ ์ถ”๊ฐ€ (#3)
  • ์ฃผ์ œ๋Š” ์†Œ์Šค ์ฝ”๋“œ๋ฅผ ๋ณด์ง€ ์•Š๊ณ ๋„ ๋ณ€๊ฒฝ ์‚ฌํ•ญ์ด ๋ฌด์—‡์ธ์ง€ ์•Œ ์ˆ˜ ์žˆ๋„๋ก ์ž‘์„ฑํ•ด์•ผ ํ•œ๋‹ค.
    • ์˜ฌ๋ฐ”๋ฅด์ง€ ์•Š์€ ์˜ˆ )ย design: CSS ์กฐ์ • (#4)
    • ์˜ณ์€ ์˜ˆ )ย design: text box์™€ layout frame ์‚ฌ์ด์— left padding ์ถ”๊ฐ€ (#4)
  • ์ปค๋ฐ‹ ๋ฉ”์‹œ์ง€๋Š” ์ œ์‚ผ์ž๊ฐ€ ๋ดค์„ ๋•Œ ๋ฌด์—‡์„ ํ–ˆ๋Š”์ง€ ํŒŒ์•…ํ•  ์ˆ˜ ์žˆ๊ฒŒ ์ž์„ธํžˆ ์ž‘์„ฑํ•œ๋‹ค.
  • ์ปค๋ฐ‹ ๋ฉ”์‹œ์ง€๋Š” ์–ด๋–ป๊ฒŒ ๋ณด๋‹จย ๋ฌด์—‡๊ณผ ์™œ๋ฅผ ์„ค๋ช…ํ•œ๋‹ค.
  • ํ•œ ์ปค๋ฐ‹์—๋Š” ํ•œ ๊ฐ€์ง€ ๊ธฐ๋Šฅ๋งŒ ๋‹ด๋Š”๋‹ค.
    • ์˜ˆ ) ํ™”๋ฉด ๊ฐœ๋ฐœ์˜ ๊ฒฝ์šฐ : ์ปดํฌ๋„ŒํŠธ ๋‹จ์œ„๋กœ ์ปค๋ฐ‹
    • ์˜ˆ2 ) ๊ธฐ๋Šฅ ๊ฐœ๋ฐœ์˜ ๊ฒฝ์šฐ : ๊ฐ ๊ธฐ๋Šฅ ๋‹จ์œ„๋กœ ์ปค๋ฐ‹


3-1-3. ์ปค๋ฐ‹ ๋ฉ”์„ธ์ง€

- fix: ์˜ฌ๋ฐ”๋ฅด์ง€ ์•Š์€ ๋™์ž‘์„ ๊ณ ์นœ ๊ฒฝ์šฐ
- feat: ์ƒˆ๋กœ์šด ๊ธฐ๋Šฅ์„ ์ถ”๊ฐ€ํ•œ ๊ฒฝ์šฐ
- refactor: ๋‚ด๋ถ€ ๋กœ์ง์€ ๋ณ€๊ฒฝํ•˜์ง€ ์•Š๊ณ  ์ฝ”๋“œ๋ฅผ ๊ฐœ์„ ํ•œ ๊ฒฝ์šฐ
- style: ์ฝ”๋“œ ๊ฐœ์„ ๊ณผ ์ƒ๊ด€์—†์ด ์‚ฌ์†Œํ•˜๊ฒŒ ์ฝ”๋“œ๋ฅผ ์ˆ˜์ •ํ•œ ๊ฒฝ์šฐ
- design: ์‚ฌ์šฉ์ž UI๋ฅผ ์ถ”๊ฐ€, ์ˆ˜์ •ํ•œ ๊ฒฝ์šฐ (๋งˆํฌ์—…, ํผ๋ธ”๋ฆฌ์‹ฑ ์ž‘์—…)
- add: ํด๋”, ํŒŒ์ผ ๋“ฑ์„ ์ถ”๊ฐ€ํ•œ ๊ฒฝ์šฐ
- move: ํด๋”, ํŒŒ์ผ, ์ฝ”๋“œ ๋“ฑ์˜ ์œ„์น˜๋ฅผ ์ด๋™ํ•œ ๊ฒฝ์šฐ
- rename: ํด๋”๋ช…, ํŒŒ์ผ๋ช… ๋“ฑ์„ ์ˆ˜์ •ํ•œ ๊ฒฝ์šฐ
- remove: ํด๋”, ํŒŒ์ผ, ์ฝ”๋“œ ๋“ฑ์„ ์‚ญ์ œํ•œ ๊ฒฝ์šฐ
- assets: ์—์…‹์„ ์ถ”๊ฐ€, ์ˆ˜์ •ํ•œ ๊ฒฝ์šฐ
- docs: ๋ฌธ์„œ๋ฅผ ์ถ”๊ฐ€, ์ˆ˜์ •ํ•œ ๊ฒฝ์šฐ
- chore: ์œ„์˜ ๋ชจ๋“  ๊ฒฝ์šฐ์— ํฌํ•จ๋˜์ง€ ์•Š๋Š” ๊ธฐํƒ€ ์ˆ˜์ •์‚ฌํ•ญ


3-2. ํ˜‘์—… ๋ฐฉ์‹

- ๊ณตํ†ต ์ด์Šˆ๋งŒ๋“ค๊ณ , ๊ณต์œ ํ•˜๊ณ  ์‹ถ์€ ๋ฌธ์ œ๊ฐ€ ์žˆ๋Š” ๊ฒฝ์šฐ ์ด์Šˆ๋กœ ์ž‘์„ฑํ•˜์—ฌ ๊ณต์œ ํ•˜๊ณ  ์ž‘์—…ํ•œ ์ด๋ ฅ ๋‚จ๊ธฐ๊ธฐ

์Šคํฌ๋ฆฐ์ƒท 2023-09-11 204309


- GitHub Project Board๋ฅผ ์ด์šฉํ•œ ์ „์ฒด ์ง„๋„ ์ƒํ™ฉ ๊ณต์œ 

์Šคํฌ๋ฆฐ์ƒท 2023-09-11 202111


- ๋‹ค๋ฅธ ํŒ€์› ์ฝ”๋“œ์˜ BUG ์ฐพ๋Š” ๊ฒฝ์šฐ ์ด์Šˆ ์ž‘์„ฑ ํ›„ Assignees ์ง€์ •

์Šคํฌ๋ฆฐ์ƒท 2023-09-11 202412


- Common ์ปดํฌ๋„ŒํŠธ ํด๋”๋ฅผ ๋”ฐ๋กœ ๊ด€๋ฆฌํ•˜์—ฌ ์ฝ”๋“œ ์žฌ์‚ฌ์šฉ์œจ ๋†’์ด๊ธฐ

์Šคํฌ๋ฆฐ์ƒท 2023-09-11 203732


- ํŽ˜์ด์ง€์˜ ๋””์ž์ธ์˜ ์ผ๊ด€์„ฑ๊ณผ ์‰ฌ์šด ์œ ์ง€๋ณด์ˆ˜๋ฅผ ์œ„ํ•ด ThemeProvider๋ฅผ ์‚ฌ์šฉ

const colors = {
  primary: '#374259',
  secondary: '#b1b5bb',
  third: '#F2D8D8',
  gray: '#dbdbdb',
  bgGray: '#f2f2f2',
  txtColor: '#767676',
  warning: '#FD7A6E',
  white: '#fff',
};

const theme = { colors };

export default theme;


3-3. Git Branch ์ „๋žต

- ์†Œ๊ทœ๋ชจ ํ”„๋กœ์ ํŠธ ๋ฐฉ์‹ ์ฑ„ํƒ

๊ทธ๋ฆผ1




4. ์—ญํ•  ๋ถ„๋‹ด

4-1. ํŒ€์› ์†Œ๊ฐœ

์ •ํ˜„๋นˆ ๋ฐ•์ง€์œค ์ด์ƒ์šฉ ๊น€๋ฏธ์ •
ํŒ€์žฅ ํŒ€์› ํŒ€์› ํŒ€์›
hyeonbinnn JiyunPark1301 yongisadragon goyomi


4-2. ์—ญํ•  ๋ถ„๋‹ด

ํ•ดํ”ผํฌ ๋งˆ์ธ๋“œ๋งต


5. ํ”„๋กœ์ ํŠธ ๊ตฌํ˜„

5-1. ์ „์ฒด UI

Frame 1



5-2. PC & Mobile

์ œ๋ชฉ ์—†์Œ



5-3. ํŽ˜์ด์ง€ ๊ธฐ๋Šฅ

์Šคํ”Œ๋ž˜์‹œ ๋กœ๊ทธ์ธ ํšŒ์›๊ฐ€์ž… & ํ”„๋กœํ•„ ์„ค์ •
์Šคํ”Œ๋ž˜์‹œ ๋กœ๊ทธ์ธ ํšŒ์›๊ฐ€์ž… ํ”„๋กœํ•„


ํ™ˆ ๊ณ„์ • ๊ฒ€์ƒ‰ ํŒ”๋กœ์šฐ & ํŒ”๋กœ์ž‰
ํ™ˆ ๊ณ„์ • ๊ฒ€์ƒ‰ ํŒ”๋กœ์šฐ ํŒ”๋กœ์ž‰


๊ฒŒ์‹œ๊ธ€ ์—…๋กœ๋“œ ๊ฒŒ์‹œ๊ธ€ ์ˆ˜์ • ๊ฒŒ์‹œ๊ธ€ ์‚ญ์ œ
๊ฒŒ์‹œ๊ธ€์ž‘์„ฑ ๊ฒŒ์‹œ๊ธ€์ˆ˜์ • ๊ฒŒ์‹œ๊ธ€์‚ญ์ œ


๋Œ“๊ธ€ ์ž‘์„ฑ ๋Œ“๊ธ€ ์‚ญ์ œ ๋Œ“๊ธ€ ์‹ ๊ณ 
๋Œ“๊ธ€์ž‘์„ฑ ๋Œ“๊ธ€์‚ญ์ œ ๋Œ“๊ธ€์‹ ๊ณ 


์ƒํ’ˆ ๋“ฑ๋ก ์ƒํ’ˆ ์ˆ˜์ • ์ƒํ’ˆ ์‚ญ์ œ
์ƒํ’ˆ๋“ฑ๋ก ์ƒํ’ˆ์ˆ˜์ • ์ƒํ’ˆ์‚ญ์ œ


ํ”„๋กœํ•„ ์ˆ˜์ • 404 ์ง€๋„
ํ”„๋กœํ•„ ์ˆ˜์ • 404 ์ง€๋„



6. ํ•ต์‹ฌ ์ฝ”๋“œ

์‹ค์‹œ๊ฐ„ ์ด๋ฉ”์ผ, ๊ณ„์ • ID ์ค‘๋ณต ๊ฒ€์‚ฌ ์‹คํ–‰

useEffect(() => {
  if (!['email', 'accountname'].includes(id)) return;

  if (
    (id === 'email' && !EMAIL_REGEX.test(formData.email)) ||
    (id === 'accountname' && !ID_REGEX.test(formData.accountname)) ||
    formData['accountname'] === userAccountname
    // ํ”„๋กœํ•„ ์ˆ˜์ • ํŽ˜์ด์ง€์—์„œ ํ˜„์žฌ ๋กœ๊ทธ์ธํ•œ ์œ ์ €์˜ accountname์ธ ๊ฒฝ์šฐ ์ด๋ฏธ ๊ฐ€์ž…๋œ ๊ณ„์ •์ด๋ผ๋Š” ์—๋Ÿฌ ๋ฉ”์„ธ์ง€๋ฅผ ๋ณด์—ฌ์ฃผ์ง€ ์•Š๊ธฐ ์œ„ํ•จ
  ) {
    return;
  }

  const errorMsg = id === 'email' ? '์ด๋ฏธ ๊ฐ€์ž…๋œ ์ด๋ฉ”์ผ ์ฃผ์†Œ ์ž…๋‹ˆ๋‹ค.' : '์ด๋ฏธ ๊ฐ€์ž…๋œ ๊ณ„์ •ID ์ž…๋‹ˆ๋‹ค.';

  const timer = setTimeout(() => {
    checkDuplication(errorMsg);
  }, 300);

  return () => {
    clearTimeout(timer);
  };
}, [formData.email, formData.accountname]);
  • email๊ณผ accountname๋งŒ ์ค‘๋ณต ๊ฒ€์‚ฌ๋ฅผ ์ง„ํ–‰ํ•˜๊ธฐ ๋•Œ๋ฌธ์— id๊ฐ€ ๋‹ค๋ฅธ ๊ฐ’์ด ๋˜๋ฉด return์„ ํ•ฉ๋‹ˆ๋‹ค.
    ๊ทธ ๋‹ค์Œ formData.email, formData.accountname์ด ๋ณ€๊ฒฝ๋  ๋•Œ๋งˆ๋‹ค ์‹คํ–‰์ด ๋ฉ๋‹ˆ๋‹ค.

  • ์กฐ๊ฑด๋ฌธ์„ ํ†ตํ•ด ์ž…๋ ฅ๋œ ์ด๋ฉ”์ผ๊ณผ ๊ณ„์ • ID์˜ ํ˜•์‹์ด ์˜ฌ๋ฐ”๋ฅธ์ง€ ํ™•์ธํ•œ ๋’ค, formData.accountname์ด ํ˜„์žฌ ๋กœ๊ทธ์ธํ•œ ์‚ฌ์šฉ์ž์˜ ๊ณ„์ • ID์™€ ์ผ์น˜ํ•˜์ง€ ์•Š๋Š”์ง€ ํ™•์ธ ํ›„, ๋งŒ์•ฝ ์กฐ๊ฑด์— ํ•ด๋‹นํ•˜์ง€ ์•Š๋Š”๋‹ค๋ฉด ํ•จ์ˆ˜๋ฅผ ์ข…๋ฃŒํ•ฉ๋‹ˆ๋‹ค.

  • ๊ทธ ์ด์™ธ์—, ์ค‘๋ณต๋œ ์ด๋ฉ”์ผ ๋˜๋Š” ๊ณ„์ • ID ์—๋Ÿฌ ๋ฉ”์‹œ์ง€๋ฅผ ์„ค์ •ํ•˜๊ณ , 300๋ฐ€๋ฆฌ์ดˆ ํ›„์— checkDuplication ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•ฉ๋‹ˆ๋‹ค.
    timer ๋ณ€์ˆ˜์—๋Š” setTimeout ํ•จ์ˆ˜๋กœ ์ƒ์„ฑ๋œ ํƒ€์ด๋จธ ID๊ฐ€ ์ €์žฅ๋˜๋ฉฐ, clearTimeout์„ ์‚ฌ์šฉํ•˜์—ฌ ํƒ€์ด๋จธ ์ทจ์†Œ๊ฐ€ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.

  • useEffect์˜ ๋ฐ˜ํ™˜ ํ•จ์ˆ˜๋Š” ํ•ด๋‹น ์ดํŽ™ํŠธ๊ฐ€ ์ •๋ฆฌ(clean-up)๋  ๋•Œ ์‹คํ–‰ํ•˜๊ณ , ์—ฌ๊ธฐ์„œ ํƒ€์ด๋จธ๋ฅผ ์ทจ์†Œํ•˜๊ธฐ ์œ„ํ•ด clearTimeout์„ ํ˜ธ์ถœํ•ฉ๋‹ˆ๋‹ค.
    ๋””๋ฐ”์šด์‹ฑ ๊ธฐ๋Šฅ์„ ์ ์šฉํ•จ์œผ๋กœ์จ ์‚ฌ์šฉ์ž๊ฐ€ ์ž…๋ ฅํ•  ๋•Œ๋งˆ๋‹ค ์„œ๋ฒ„์š”์ฒญ์„ ํ•˜์ง€ ์•Š๊ธฐ์— ํ†ต์‹  ๋น„์šฉ์ด ๋ฐœ์ƒํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.



์ด๋ฏธ์ง€ ์—…๋กœ๋“œ๋ฅผ ์œ„ํ•œ ์ปค์Šคํ…€ ํ›…

import { useState } from 'react';
import { uploadImages } from '../api/image';

const ALLOWED_EXTENSIONS = ['.jpg', '.gif', '.png', '.jpeg', '.bmp', '.tif', '.heic'];
const MAX_SIZE = 10 * 1024 * 1024;

const useImagesUpload = () => {
  const [images, setImages] = useState([]);

  const onUpload = async (files, length) => {
    if (images.length + length > 3) return alert('์ด๋ฏธ์ง€๋Š” ์ตœ๋Œ€ 3๊ฐœ๊นŒ์ง€ ์—…๋กœ๋“œ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.');

    const formData = new FormData();
    for (let i = 0; i < length; i++) {
      const file = files[i];

      const fileExtension = file.name.split('.').pop().toLowerCase();
      if (ALLOWED_EXTENSIONS.includes(`.${fileExtension}`) && file.size <= MAX_SIZE) {
        formData.append('image', file);
      }
    }

    try {
      const data = await uploadImages(formData);
      const filenames = data.map((data) => data.filename);
      setImages((prev) => [...prev, ...filenames]);
    } catch (error) {
      console.log(error.message);
    }
  };

  const onDelete = (index) => {
    setImages((prevImages) => {
      const updatedImages = [...prevImages];
      updatedImages.splice(index, 1);
      return updatedImages;
    });

    alert('์‚ญ์ œ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.');
  };

  return { images, onUpload, onDelete };
};

export default useImagesUpload;
  • ์ด๋ฏธ์ง€ ์—…๋กœ๋“œ๋Š” ํŠน์„ฑ์ƒ ํšŒ์›๊ฐ€์ž… ์‹œ ํ”„๋กœํ•„ ์„ค์ •, ํ”„๋กœํ•„ ์ˆ˜์ •, ๊ฒŒ์‹œ๊ธ€ ์ž‘์„ฑ, ์ƒํ’ˆ ๋“ฑ๋ก ๋“ฑ ์—ฌ๋Ÿฌ ํŽ˜์ด์ง€์—์„œ ๋ฐ˜๋ณต์ ์œผ๋กœ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ ์—ฌ๋Ÿฌ ์ด๋ฏธ์ง€๋ฅผ ์—…๋กœ๋“œ ํ•  ์ˆ˜ ์žˆ๋Š” ์ƒํƒœ๋ฅผ ์„ ์–ธํ•˜๊ณ , ์ƒˆ๋กญ๊ฒŒ ๋“ค์–ด์˜ค๋Š” ์ด๋ฏธ์ง€๋“ค๊ณผ ๊ธฐ์กด ์ด๋ฏธ์ง€๋ฅผ ํ•ฉ์นœ ๊ฐ’์ด 3์ด ๋„˜์œผ๋ฉด ๋” ์ด์ƒ ์—…๋กœ๋“œ ํ•  ์ˆ˜ ์—†๋„๋ก ๊ตฌํ˜„ํ•ฉ๋‹ˆ๋‹ค.

  • FormData ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๊ณ , files ๋ฐฐ์—ด์„ ์ˆœํšŒํ•˜๋ฉด์„œ ํ—ˆ์šฉ๋˜๋Š” ํ™•์žฅ์ž ๋ชฉ๋ก๊ณผ ์ด๋ฏธ์ง€ ์‚ฌ์ด์ฆˆ๋ฅผ ๊ฒ€์‚ฌํ•œ ๋’ค, ํ†ต๊ณผํ•œ๋‹ค๋ฉด formData์— image ๋ผ๋Š” ํ‚ค ๊ฐ’์œผ๋กœ ํŒŒ์ผ์„ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

  • ๊ทธ ๋‹ค์Œ uploadImages ํ•จ์ˆ˜๋ฅผ ํ†ตํ•ด ์„œ๋ฒ„์— ์ด๋ฏธ์ง€๋ฅผ ์—…๋กœ๋“œํ•˜๊ณ , ์„œ๋ฒ„ ์‘๋‹ต์—์„œ ํŒŒ์ผ๋ช…์„ ์ถ”์ถœํ•˜์—ฌ ์ƒํƒœ๋ฅผ ์—…๋ฐ์ดํŠธํ•˜๊ณ , setImages ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•ด ์ด์ „ ์ƒํƒœ๊ฐ’์ธ prev ๋ฐฐ์—ด๊ณผ ์ƒˆ๋กœ์šด ํŒŒ์ผ๋ช… ๋ฐฐ์—ด์ธ filenames๋ฅผ ํ•ฉ์ณ์„œ ์ƒํƒœ๋ฅผ ๊ฐฑ์‹ ํ•ฉ๋‹ˆ๋‹ค.

  • ์ด๋ ‡๊ฒŒ ํ•จ์œผ๋กœ์จ, ์ด๋ฏธ์ง€ ์—…๋กœ๋“œ ํ›„์˜ ์ƒํƒœ๊ฐ’์„ ์—…๋ฐ์ดํŠธํ•˜๊ณ  React ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋ฆฌ๋ Œ๋”๋ง๋  ์ˆ˜ ์žˆ๋„๋ก ํ•ฉ๋‹ˆ๋‹ค.




7. ํŠธ๋Ÿฌ๋ธ” ์ŠˆํŒ…

๋ฐ˜๋ณต๋˜๋Š” API ์š”์ฒญ ์ž‘์—…์„ ์ค„์ด๊ธฐ ์œ„ํ•ด ํŒŒ์ผ ๋ถ„๋ฆฌํ•˜๊ธฐ

const BASE_URL = 'https://api.mandarin.weniv.co.kr';

export const request = async (url, options) => {
  try {
    const response = await fetch(`${BASE_URL}/${url}`, {
      ...options,
      headers: {
        'Content-Type': 'application/json',
        ...options.headers,
      },
    });

    if (response.ok) {
      const data = await response.json();
      return data;
    }
  } catch (err) {
    console.log(err);
  }
};

export const imageRequest = async (url, options) => {
  try {
    const response = await fetch(`${BASE_URL}/${url}`, { ...options });

    if (response.ok) {
      const data = await response.json();
      return data;
    }
  } catch (err) {
    console.log(err);
  }
};
  • ๊ฐ€์žฅ ๊ธฐ๋ณธ์ด ๋˜๋Š” request ํ•จ์ˆ˜๋ฅผ ๋งŒ๋“ค์–ด ์ค๋‹ˆ๋‹ค. ๊ทธ ๋‹ค์Œ, ๋กœ๊ทธ์ธ์€ auth.js , ๊ฒŒ์‹œ๊ธ€์€ post.js , ์ƒํ’ˆ์€ product.js ๋“ฑ ๊ธฐ๋Šฅ๋ณ„๋กœ ํŒŒ์ผ์„ ๋งŒ๋“ญ๋‹ˆ๋‹ค.


import { request } from './request';

// ํšŒ์›๊ฐ€์ž…
export const join = async (state, formData, image) => {
  return await request('user', {
    method: 'POST',
    body: JSON.stringify({ user: { ...state, ...formData, image } }),
  });
};

// ๋กœ๊ทธ์ธ
export const login = async (email, password) => {
  return await request('user/login', {
    method: 'POST',
    body: JSON.stringify({ user: { email, password } }),
  });
};

// ํ† ํฐ ๊ฒ€์ฆ
// ...

// ์ด๋ฏธ ์กด์žฌํ•˜๋Š” ์ด๋ฉ”์ผ(๋˜๋Š” ๊ณ„์ •)์ธ์ง€ ๊ฒ€์‚ฌ
export const validateForm = async (id, formData) => {
  return await request(`user/${id}valid`, {
    method: 'POST',
    body: JSON.stringify({ user: { [id]: formData[id] } }),
  });
};
  • ํŒŒ์ผ ๋‚ด์—์„œ ํ•„์š”ํ•œ ์š”์ฒญ๋“ค ์ฆ‰, auth.js๋Š” ํšŒ์›๊ฐ€์ž…, ๋กœ๊ทธ์ธ ๋“ฑ post.js๋Š” ๊ฒŒ์‹œ๊ธ€ ๋ถˆ๋Ÿฌ์˜ค๊ธฐ, ์—…๋กœ๋“œ, ์ˆ˜์ •, ์‚ญ์ œ, ์‹ ๊ณ  ๋“ฑ ๊ฐ๊ฐ์˜ ํ•จ์ˆ˜๋กœ ๋งŒ๋“ค์–ด ์ค๋‹ˆ๋‹ค.

  • ๊ทธ๋ฆฌ๊ณ  ๊ฐ๊ฐ์˜ ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ๋Š” ๋จผ์ € import ํ•ด์ฃผ๊ณ , api๋ฅผ ๊ฐ€์ ธ์˜จ ํ›„ ํ•„์š”ํ•œ ์ธ์ž ๊ฐ’๋“ค์„ ๋„˜๊ฒจ์ฃผ๋ฉด ๋ฉ๋‹ˆ๋‹ค.



ํ™”๋ฉด ์บก์ฒ˜ 2023-12-14 201943





About

๐Ÿพ ๋ฐ˜๋ ค๋™๋ฌผ ํ†ตํ•ฉ ์ปค๋ฎค๋‹ˆํ‹ฐ ์„œ๋น„์Šค

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages