Skip to content

Latest commit

ย 

History

History
412 lines (367 loc) ยท 22.9 KB

README.md

File metadata and controls

412 lines (367 loc) ยท 22.9 KB

FOODZIP

image

๋ฐฐํฌ ์‚ฌ์ดํŠธ : https://foodzip.netlify.app/

๐Ÿ–ฅ ํ”„๋กœ์ ํŠธ ์†Œ๊ฐœ

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

๊ฐœ๋ฐœ ๊ธฐ๊ฐ„

แ„€แ…ขแ„‡แ…กแ†ฏแ„€แ…ตแ„€แ…กแ†ซ

๐Ÿง‘โ€๐Ÿคโ€๐Ÿง‘ ์–ด? ๊ธˆ์ง€์˜ ์กฐ์› ์†Œ๊ฐœ


์ด์ง€์ˆ˜
์กฐ์žฅ


๊น€์œจ์ด
์กฐ์›


์œค์„ ํ˜ธ
์กฐ์›


์ด์€์ฃผ
์กฐ์›

์—ญํ•  ๋ถ„๋‹ด

แ„‹แ…งแ†จแ„’แ…กแ†ฏแ„‡แ…ฎแ†ซแ„ƒแ…กแ†ท

ํŒ€ ๋ฌธํ™”

  • ํˆฌ๋ช…ํ•œ ์ •๋ณด ๊ณต์œ  : ํ˜‘์—…์— ์žˆ์–ด ์„œ๋กœ์˜ ์ž‘์—…์— ๋Œ€ํ•œ ์ดํ•ด๋ฅผ ๊นŠ๊ฒŒ ํ•ฉ๋‹ˆ๋‹ค.

  • ์‹ ์†ํ•œ ์˜๊ฒฌ ์กฐ์œจ : ์‹คํ–‰ ์†๋„์™€ ์ฑ…์ž„๊ฐ์ด ๋†’์•„์ง‘๋‹ˆ๋‹ค.

  • ์ง„์ž…์žฅ๋ฒฝ ๋‚ฎ์ถ”๊ธฐ : ํŒ€ ๊ฐ„์˜ ์ง„์ž…์žฅ๋ฒฝ์„ ๋‚ฎ์ถ”๊ณ , ํŒ€์› ๋ชจ๋‘๊ฐ€ ํ”„๋กœ์ ํŠธ์— ์ ๊ทน์ ์œผ๋กœ ์ฐธ์—ฌ ํ•˜๋Š” ํ™˜๊ฒฝ์„ ๋งŒ๋“ค์—ˆ์Šต๋‹ˆ๋‹ค.

  • ๊ฑด๊ฐ•ํ•œ ํŒ€ ๋ถ„์œ„๊ธฐ : ์›ํ™œํ•œ ์˜์‚ฌ์†Œํ†ต์„ ํ†ตํ•ด ์ƒํ˜ธ ์‹ ๋ขฐ๋ฅผ ์Œ“์•„๊ฐ‘๋‹ˆ๋‹ค. ๊ฒฐ๊ณผ์ ์œผ๋กœ ๋ชจ๋“  ํŒ€์›์ด ํ”„๋กœ์ ํŠธ๋ฅผ ์ ๊ทน์ ์œผ๋กœ ์ฐธ์—ฌํ•˜๋Š” ๋ถ„์œ„๊ธฐ๋ฅผ ์กฐ์„ฑํ–ˆ์Šต๋‹ˆ๋‹ค.

  • ํ˜‘์—…์˜ ํšจ์œจ์„ฑ ๊ทน๋Œ€ํ™” : ํ”ผ๋“œ๋ฐฑ ๊ณผ์ •์„ ํ†ตํ•ด ์ž‘์—… ๊ณผ์ •์„ ๊ฐœ์„ ํ•˜๊ณ  ํŒ€์›๋“ค๋ผ๋ฆฌ ์„œ๋กœ๋ฅผ ํ™˜๊ธฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๐Ÿ›  ํ…Œํฌ ์Šคํƒ

๐Ÿ‘จโ€๐Ÿ‘ฉโ€๐Ÿ‘งโ€๐Ÿ‘ง ํ˜‘์—… ํˆด

๐Ÿ“„ ํŽ˜์ด์ง€ ์†Œ๊ฐœ

์Šคํ”Œ๋ž˜์‹œ ํšŒ์›๊ฐ€์ž…
ใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…ค
- ์•ฑ ์‹œ์ž‘ํ™”๋ฉด
- ์ž๋™ ๋กœ๊ทธ์ธ ์‹œ ํ™ˆํ”ผ๋“œ๋กœ ์ด๋™
- ๋กœ๊ทธ์ธ ์•ˆ ํ•œ ๊ฒฝ์šฐ ์›ฐ์ปด ํŽ˜์ด์ง€ ์ด๋™
ใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…ค
ใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…ค
- ์ด๋ฉ”์ผ, ๋น„๋ฐ€๋ฒˆํ˜ธ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ
- ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ ํ†ต๊ณผ ์‹œ ๋ฒ„ํŠผ ํ™œ์„ฑํ™”
ใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…ค
ํ”„๋กœํ•„ ์„ค์ • ๋กœ๊ทธ์ธ
ใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…ค
- ๊ณ„์ • ID ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ
- ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ ํ†ต๊ณผ ์‹œ ๋ฒ„ํŠผ ํ™œ์„ฑํ™”
- ์ด๋ฏธ์ง€ ๋ฏธ์„ค์ • ์‹œ ๊ธฐ๋ณธ ํ”„๋กœํ•„ ์ด๋ฏธ์ง€ ์ ์šฉ
ใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…ค
ใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…ค
- ์ด๋ฉ”์ผ, ๋น„๋ฐ€๋ฒˆํ˜ธ ๋ชจ๋‘ ์ž…๋ ฅ ์‹œ ๋ฒ„ํŠผ ํ™œ์„ฑํ™”
- ๋กœ์ปฌ์Šคํ† ๋ฆฌ์ง€์— ํ† ํฐ ์ €์žฅ
- ๋กœ๊ทธ์ธ ์„ฑ๊ณต ์‹œ ํ™ˆํ”ผ๋“œ๋กœ ์ด๋™
ใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…ค
๊ฒ€์ƒ‰ ํŒ”๋กœ์šฐ ํŽ˜์ด์ง€
ใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…ค
- ์œ ์ € ๊ฒ€์ƒ‰
- ํด๋ฆญ ์‹œ ํ”„๋กœํ•„๋กœ ์ด๋™
- debounce ์ด์šฉ
ใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…ค
ใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…ค
- ์œ ์ € ํŒ”๋กœ์šฐ, ์–ธํŒ”๋กœ์šฐ ๊ธฐ๋Šฅ
- ์œ ์ € ํ”„๋กœํ•„ ํŽ˜์ด์ง€ ์ด๋™
ใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…ค
์ฑ„ํŒ… ์—…๋กœ๋“œ ํŽ˜์ด์ง€
ใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…ค
- ์ฑ„ํŒ… ํŽ˜์ด์ง€ ๊ตฌํ˜„
ใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…ค
ใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…ค
- ๊ฒŒ์‹œ๋ฌผ ์—…๋กœ๋“œ ๊ธฐ๋Šฅ
- ์ด๋ฏธ์ง€ ์••์ถ• ๊ธฐ๋Šฅ
- ์ด๋ฏธ์ง€ 3์žฅ ์—…๋กœ๋“œ ๋ฐ ๋“œ๋ž˜๊ทธ ์•ค ๋“œ๋ž ๊ธฐ๋Šฅ
ใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…ค
๊ฒŒ์‹œ๋ฌผ ์ˆ˜์ • ๊ฒŒ์‹œ๋ฌผ ์‚ญ์ œ
ใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…ค
- ๊ฒŒ์‹œ๋ฌผ ์ด๋ฏธ์ง€ ๋ฐ ๋‚ด์šฉ ๋ณ€๊ฒฝ ๊ฐ€๋Šฅ
ใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…ค
ใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…ค
- ๊ฒŒ์‹œ๋ฌผ ์‚ญ์ œ ๊ธฐ๋Šฅ
ใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…ค
ํ”„๋กœํ•„ ํŽ˜์ด์ง€ ํ”„๋กœํ•„ ์ˆ˜์ • ํŽ˜์ด์ง€
ใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…ค
- ๊ฒŒ์‹œ๊ธ€ ๋ฆฌ์ŠคํŠธํ˜•, ์•จ๋ฒ”ํ˜•
ใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…ค
ใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…ค
- ํ”„๋กœํ•„ ์ •๋ณด๋ฅผ ์œ ์ง€ํ•œ ์ƒํƒœ๋กœ ์ˆ˜์ • ํŽ˜์ด์ง€ ์ด๋™
- accountname ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ
- validation์„ ํ†ต๊ณผํ•ด์•ผ ์ˆ˜์ • ๊ฐ€๋Šฅ
ใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…ค
์ถ”์ฒœ๋ง›์ง‘ ์นด์นด์˜ค๋งต
ใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…ค
- ์ถ”์ฒœ๋ง›์ง‘ ๋“ฑ๋ก, ์ˆ˜์ •, ์‚ญ์ œ ๊ธฐ๋Šฅ
ใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…ค
ใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…ค
- ์นด์นด์˜ค๋งต API๋ฅผ ์ด์šฉํ•˜์—ฌ ์ถ”์ฒœ ๋ง›์ง‘ ์œ„์น˜ ํ™•์ธ
ใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…ค
๊ฒŒ์‹œ๋ฌผ ์ƒ์„ธ ํŽ˜์ด์ง€ ๋žœ๋ค ์Œ์‹ ์ถ”์ฒœ
ใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…ค
- ๋Œ“๊ธ€ ๋“ฑ๋ก, ์‚ญ์ œ, ์‹ ๊ณ  ๊ธฐ๋Šฅ
- ์ข‹์•„์š” ๊ธฐ๋Šฅ
ใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…ค
ใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…ค
- ๋กœ๊ณ  ํด๋ฆญ ์‹œ ๋žœ๋ค ์Œ์‹ ์ถ”์ฒœ ๊ธฐ๋Šฅ
ใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…ค
SNS ๊ณต์œ ํ•˜๊ธฐ ๋กœ๊ทธ์•„์›ƒ
ใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…ค
- ์ถ”์ฒœ๋ง›์ง‘ ์‹๋‹น SNS๋กœ ๊ณต์œ  ๊ฐ€๋Šฅ
ใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…ค
ใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…ค
- ๋กœ๊ทธ์•„์›ƒ ์‹œ ์›ฐ์ปด ํŽ˜์ด์ง€๋กœ ์ด๋™
- ๋กœ์ปฌ์Šคํ† ๋ฆฌ์ง€์—์„œ ํ† ํฐ ์‚ญ์ œ
ใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…คใ…ค

๐Ÿ“Œ ์ฃผ์š” ๊ธฐ๋Šฅ ์†Œ๊ฐœ

์ฝ”๋“œ ์„ค๋ช…
import useForm react-hook-form ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์‚ฌ์šฉ์„ ์œ„ํ•ด useForm์„ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค.
useForm useForm ํ›…์„ ํ˜ธ์ถœํ•˜์—ฌ ํ•„์š”ํ•œ ๋ฉ”์†Œ๋“œ์™€ ์†์„ฑ์„ ์ถ”์ถœํ•ฉ๋‹ˆ๋‹ค. ์ด ํ†ตํ•ด ์ž…๋ ฅ, ์ œ์ถœ, ์˜ค๋ฅ˜ ๋ฐ ์œ ํšจ์„ฑ์„ ์ฒ˜๋ฆฌํ•˜๊ธฐ ์œ„ํ•œ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. mode: "onChange"๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ž…๋ ฅ ๊ฐ’์˜ ๋ณ€ํ™”๋ฅผ ๊ฐ์ง€ํ•˜๋ฉด์„œ ๋™์‹œ์— ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ๋ฅผ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค.
setError ํผ ์ปจํŠธ๋กค์˜ ์˜ค๋ฅ˜ ์ƒํƒœ๋ฅผ ์ˆ˜๋™์œผ๋กœ ์„ค์ • ๋˜๋Š” ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ๋Š” ํ•จ์ˆ˜์ž…๋‹ˆ๋‹ค.
name: ์˜ค๋ฅ˜ ์ƒํƒœ๋ฅผ ์„ค์ •ํ•˜๋ ค๋Š” ํผ ์ปจํŠธ๋กค์˜ ์ด๋ฆ„.
type: ์˜ค๋ฅ˜ ์œ ํ˜•(์˜ˆ: "required", "pattern", "custom" ๋“ฑ).
message: ์‚ฌ์šฉ์ž์—๊ฒŒ ํ‘œ์‹œํ•  ์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€.
์ž…๋ ฅ ํผ Register๋ฅผ ํ†ตํ•ด value๋ฅผ ์ œ์–ดํ•˜๊ณ  required์™€ pattern ์„ ํ†ตํ•ด API ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ ์ด์ „์— ํŒจํ„ด ์œ ํšจ์„ฑ๊ฒ€์‚ฌ๋ฅผ ์ง„ํ–‰ํ•ฉ๋‹ˆ๋‹ค.
validate pattern์€ ํ˜•์‹์„ ๊ฒ€์ฆํ•˜๊ณ  validate๋Š” ์กฐ๊ฑด์„ ๊ฒ€์ฆํ•ฉ๋‹ค
import { useForm } from "react-hook-form";

const {
    register,
    handleSubmit,
    clearErrors,
    setError,
    getValues,
    formState: { errors, isValid },
  } = useForm({
    mode: "onChange",
    defaultValues: {
      // ์ดˆ๊ธฐ๊ฐ’
    },
  });
  const checkEmailValid = async email => {
    try {
      const res = await axios.post(

      // ์ด๋ฉ”์ผ Validation API

      const reqMsg = res.data.message;
      clearErrors("email");
      if (reqMsg === "์ด๋ฏธ ๊ฐ€์ž…๋œ ์ด๋ฉ”์ผ ์ฃผ์†Œ ์ž…๋‹ˆ๋‹ค.") {
        setError("email", {
          type: "manual",
          message: "์ด๋ฏธ ๊ฐ€์ž…๋œ ์ด๋ฉ”์ผ ์ฃผ์†Œ ์ž…๋‹ˆ๋‹ค.",
        });
        return false;
      } else {
        clearErrors("email");
        return true;
  return (
    <StyledForm onSubmit={handleSubmit(handleFormSubmit)}>
      <StyledInputContainer>
        <StyledLabel htmlFor="email">์ด๋ฉ”์ผ</StyledLabel>
        <StyledInput
          {...register("email", {
            required: "์ด๋ฉ”์ผ์€ ํ•„์ˆ˜ ์ž…๋ ฅ์ž…๋‹ˆ๋‹ค.",
            pattern: {
              value: /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i,
              message: "์œ ํšจํ•œ ์ด๋ฉ”์ผ ์ฃผ์†Œ๋ฅผ ์ž…๋ ฅํ•˜์„ธ์š”.",
            },
          })}
        />
        {errors.email && (
          <StyledError role="alert">{errors.email.message}</StyledError>
        )}
      </StyledInputContainer>
      // ์ด๋ฉ”์ผ ๋ถ€๋ถ„๊ณผ ๋™์ผ
            validate: {
              matchesPreviousPassword: value => {
                const { password } = getValues();
                return password === value || "๋น„๋ฐ€๋ฒˆํ˜ธ๊ฐ€ ์ผ์น˜ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.";
์ฝ”๋“œ ์„ค๋ช…
useEffect
useDebounce
๋‹ค์Œ์€ useEffect์™€ useDebounce๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๊ฒ€์ƒ‰ ํ‚ค์›Œ๋“œ๊ฐ€ ์—…๋ฐ์ดํŠธ๋  ๋•Œ๋งˆ๋‹ค ๊ฒ€์ƒ‰ API๋ฅผ ํ˜ธ์ถœํ•˜๊ณ  ๊ฒฐ๊ณผ๋ฅผ ํ•„ํ„ฐ๋งํ•˜๋Š” ์ฝ”๋“œ์ž…๋‹ˆ๋‹ค.
useDebounce๋Š” ์ผ์ • ์‹œ๊ฐ„ ๋™์•ˆ์˜ ์ž…๋ ฅ์ด ๋ฉˆ์ถ˜ ํ›„ API ์š”์ฒญ์ด ๋  ์ˆ˜ ์žˆ๋„๋ก ์ œ์–ดํ•ด ๋ถˆํ•„์š”ํ•œ API ํ˜ธ์ถœ์„ ๋ฐฉ์ง€ํ•ฉ๋‹ˆ๋‹ค.
useEffect๋Š” ๋””๋ฐ”์šด์Šค๋œ ํ‚ค์›Œ๋“œ๊ฐ€ ๋ณ€๊ฒฝ๋  ๋•Œ๋งˆ๋‹ค ๊ฒฐ๊ณผ ๋ชฉ๋ก์„ ์—…๋ฐ์ดํŠธํ•ฉ๋‹ˆ๋‹ค. ์ถ”๊ฐ€๋กœ ์กฐ๊ฑด์— ๋”ฐ๋ผ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฑธ๋Ÿฌ๋‚ด์–ด ๋ถˆํ•„์š”ํ•œ ์ด๋ฏธ์ง€ ๋กœ๋”ฉ๊ณผ ์ฒ˜๋ฆฌ์‹œ๊ฐ„์„ ์ค„์ผ์ˆ˜ ์žˆ๊ฒŒ ์„ค๊ณ„ํ–ˆ์Šต๋‹ˆ๋‹ค.
  const [debouncedSearchKeyword] = useDebounce(searchKeyword, 300);

  useEffect(() => {
    const fetchData = async () => {
      if (!debouncedSearchKeyword) {
        return;
      } else {

        // ๊ฒ€์ƒ‰ API ์ฝ”๋“œ ๋ถ€๋ถ„

          const filteredData = response.data.filter(
            item => !item.image.startsWith("https://mandarin.api.weniv"),
          );
          setSearchListData(filteredData);
        } 
    };
...
    fetchData();
  }, [debouncedSearchKeyword]);
์ฝ”๋“œ ์„ค๋ช…
elapsedTime ๋Œ“๊ธ€์ด ์ž‘์„ฑ๋œ ์‹œ๊ฐ„๊ณผ ํ˜„์žฌ ์‹œ๊ฐ„ ์‚ฌ์ด์˜ ๊ฒฝ๊ณผ ์‹œ๊ฐ„์„ ๊ณ„์‚ฐํ•˜์—ฌ ๋ฌธ์ž์—ด๋กœ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค. ๊ฒฝ๊ณผ ์‹œ๊ฐ„์€ ๋…„, ๊ฐœ์›”, ์ผ, ์‹œ๊ฐ„, ๋ถ„ ๋“ฑ์˜ ๋‹จ์œ„๋กœ ํ‘œํ˜„๋˜๋ฉฐ, ๊ฐ€์žฅ ํฐ ๋‹จ์œ„๋ถ€ํ„ฐ ๊ณ„์‚ฐ๋˜๋ฉฐ ๋ฌธ์ž์—ด๋กœ ๋ฐ˜ํ™˜๋ฉ๋‹ˆ๋‹ค.
const elapsedTime = commentDate => {
    const now = new Date();
    const commentTime = new Date(commentDate);
    const elapsedSeconds = Math.floor((now - commentTime) / 1000);

    const times = [
      { name: "๋…„", seconds: 60 * 60 * 24 * 365 },
      { name: "๊ฐœ์›”", seconds: 60 * 60 * 24 * 30 },
      { name: "์ผ", seconds: 60 * 60 * 24 },
      { name: "์‹œ๊ฐ„", seconds: 60 * 60 },
      { name: "๋ถ„", seconds: 60 },
    ];

    for (const value of times) {
      const elapsed = Math.floor(elapsedSeconds / value.seconds);

      if (elapsed > 0) {
        return `${elapsed}${value.name} ์ „`;
      }
    }
    return "๋ฐฉ๊ธˆ ์ „";
  };
์ฝ”๋“œ ์„ค๋ช…
const { kakao }= window; ์นด์นด์˜ค API์—์„œ ์ œ๊ณตํ•˜๋Š” ๊ธฐ๋Šฅ๋“ค์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ๊ตฌํ˜„๋œ ๊ฐ์ฒด์ž…๋‹ˆ๋‹ค.
useState, useEffect Map ์ปดํฌ๋„ŒํŠธ ์ดˆ๊ธฐํ™”, ์‚ฌ์šฉ์ž ์œ„๋„, ๊ฒฝ๋„์— ๋”ฐ๋ฅธ ์ง€๋„ ๋งˆ์ปค ํ‘œ์‹œ ์„ค์ •. ์ƒํƒœ ์œ ์ง€์™€ ์ปดํฌ๋„ŒํŠธ ๋ผ์ดํ”„ ์‚ฌ์ดํด์— ๋งž์ถฐ ๋™์ž‘ํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.
๊ฒ€์ƒ‰ ์ง€๋„ ๋งˆ์ปค ์ƒ์„ฑ ๊ฒ€์ƒ‰๋œ ์œ„์น˜์˜ ๋งˆ์ปค์™€ ์˜ค๋ฒ„๋ ˆ์ด๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ๊ด€๋ จ ํด๋ฆญ ์ด๋ฒคํŠธ๋ฅผ ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค.
const { kakao } = window;

const MapTest = () => {
  const [place, setPlace] = useState("");
  const [map, setMap] = useState(null);
  const location = useLocation();
  const data = location.state;
  const recommendName = data.restaurantname;

  useEffect(() => {
    let container = document.getElementById("map");
    let options = { center: new kakao.maps.LatLng(37.5045, 127.049) };
    let kakaoMap = new kakao.maps.Map(container, options);
    setMap(kakaoMap);
  }, []);
  useEffect(() => {
    if (map && recommendName) {
      const ps = new kakao.maps.services.Places();
      ps.keywordSearch(recommendName, placesSearchCB);
      function placesSearchCB(data, status, pagination) {
        if (status === kakao.maps.services.Status.OK) {
          let bounds = new kakao.maps.LatLngBounds();
          for (let i = 0; i < data.length; i++) {
            displayMarker(data[i]);
            bounds.extend(new kakao.maps.LatLng(data[i].y, data[i].x));
          }
          map.setBounds(bounds);
        }
      }
      function displayMarker(place) {
        const imageSize = new kakao.maps.Size(45, 45);
        const imageSrc = Marker;
        let markerImage = new kakao.maps.MarkerImage(imageSrc, imageSize);
        let marker = new kakao.maps.Marker({
          // ๋งˆ์ปค ์ปค์Šคํ…€
        });
        let content =
          // ์ง€๋„ Overlay ์ปค์Šคํ…€
        setPlace(place.road_address_name);
        let customOverlay = new kakao.maps.CustomOverlay({
          position: new kakao.maps.LatLng(place.y, place.x),
          content: content,
          yAnchor: 1,
        });

        kakao.maps.event.addListener(marker, "click", function () {
          customOverlay.setMap(map);
        });
      }
    }
  }, [recommendName, map]);
์ฝ”๋“œ ์„ค๋ช…
options ์ด๋ฏธ์ง€ ์••์ถ•์— ์‚ฌ์šฉ๋˜๋Š” ์˜ต์…˜์„ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค. ์ด๋ฏธ์ง€ ์ตœ๋Œ€ ํฌ๊ธฐ, ์ตœ๋Œ€ ๋„ˆ๋น„ ๋˜๋Š” ๋†’์ด, ์›น ์ž‘์—…์ž ์‚ฌ์šฉ ์—ฌ๋ถ€๋ฅผ ์„ค์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
์ด๋ฏธ์ง€ ์••์ถ•
๋ณ€ํ™˜
์„ ํƒํ•œ ํŒŒ์ผ์„ ์••์ถ•ํ•˜๊ณ  ์ด๋ฅผ ๋ฏธ๋ฆฌ๋ณด๊ธฐ๋กœ ํ‘œ์‹œํ•˜๋ฉฐ, ๋ฐ์ดํ„ฐ URL๋กœ ๋ณ€ํ™˜ํ•œ ํ›„, ์ด๋ฏธ์ง€๋ฅผ ํ•ธ๋“ค๋งํ•˜๋Š”๋ฐ ํ•„์š”ํ•œ ์—…๋กœ๋“œ ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•ฉ๋‹ˆ๋‹ค.
formDataHandler base64 ๋ฐ์ดํ„ฐ URI๋ฅผ blob์œผ๋กœ ๋ณ€ํ™˜ํ•˜๊ณ , ์ด๋ฅผ ๋‹ค์‹œ File ๊ฐ์ฒด๋กœ ๋ณ€ํ™˜ํ•˜๋Š” ํ•จ์ˆ˜์ž…๋‹ˆ๋‹ค.
import imageCompression from "browser-image-compression";
const options = {
      maxSizeMB: 0.7,
      maxWidthOrHeight: 500,
      useWebWorker: true,
    };
    try {
      const compressedFile = await imageCompression(file, options);
      setBoardImage(compressedFile);
      const promise = imageCompression.getDataUrlFromFile(compressedFile);
      promise.then(result => {
        setUploadPreview(result);
      });
      const reader = new FileReader();
      reader.readAsDataURL(compressedFile);
      reader.onloadend = () => {
        const base64data = reader.result;
        const imageUrl = formDataHandler(base64data);
        onImageUrlChange(file, imageUrl);
        setImgUrl(imageUrl);
      };
    } catch (error) {
      console.log(error);
    }
  };
  const formDataHandler = async dataURI => {
    const byteString = atob(dataURI.split(",")[1]);
    const ab = new ArrayBuffer(byteString.length);
    const ia = new Uint8Array(ab);
    for (let i = 0; i < byteString.length; i++) {
      ia[i] = byteString.charCodeAt(i);
    }
    const blob = new Blob([ab], { type: "image/jpeg" });
    const file = new File([blob], "image.jpg", { type: "image/jpeg" });
    return file;
  };

๋ฆฌํŒฉํ† ๋ง & ๋ฒ„์ „์—…

  • API ๋ถ„๋ฆฌ
  • ์ „์—ญ์ƒํƒœ๊ด€๋ฆฌ(Recoil)๋ฅผ ์ด์šฉํ•œ ๋ชจ๋‹ฌ ๊ด€๋ฆฌ
  • ๋ฌดํ•œ ์Šคํฌ๋กค
  • ์ด๋ฏธ์ง€ ์Šคํ”„๋ผ์ดํŠธ ๊ธฐ๋ฒ•
  • ์›น ์ ‘๊ทผ์„ฑ ๊ฐœ์„ 
  • sns ๊ณต์œ ํ•˜๊ธฐ ๊ธฐ๋Šฅ
  • ์ด๋ฏธ์ง€ ์ตœ๋Œ€ 3์žฅ๊นŒ์ง€ ๋“ฑ๋ก(๋“œ๋ž˜๊ทธ ์•ค ๋“œ๋ž์œผ๋กœ ์ˆœ์„œ ๋ณ€๊ฒฝ ๊ฐ€๋Šฅ)
  • ํƒ‘๋ฒ„ํŠผ

๐Ÿ—‚๏ธ ํด๋” ๊ตฌ์กฐ

    src
      โ”œโ”€ App.js
      โ”œโ”€ components
      โ”‚  โ”œโ”€ Auth
      โ”‚  โ”œโ”€ Chat
      โ”‚  โ”œโ”€ Comment
      โ”‚  โ”œโ”€ common
      โ”‚  โ”‚  โ”œโ”€ Button
      โ”‚  โ”‚  โ”œโ”€ Header
      โ”‚  โ”‚  โ””โ”€ Nav
      โ”‚  โ”œโ”€ Error
      โ”‚  โ”œโ”€ Feed
      โ”‚  โ”œโ”€ FollowItem
      โ”‚  โ”œโ”€ Modal
      โ”‚  โ”œโ”€ Post
      โ”‚  โ”‚  โ”œโ”€ ImgPrev
      โ”‚  โ”‚  โ”œโ”€ PostEdit
      โ”‚  โ”‚  โ”œโ”€ PostItem
      โ”‚  โ”‚  โ”œโ”€ PostList
      โ”‚  โ”‚  โ””โ”€ StarRating
      โ”‚  โ”œโ”€ Profile
      โ”‚  โ”œโ”€ Search
      โ”‚  โ””โ”€ styles
      โ”œโ”€ pages
      โ”‚  โ”œโ”€ AuthorPage
      โ”‚  โ”‚  โ”œโ”€ Login
      โ”‚  โ”‚  โ””โ”€ SignUp
      โ”‚  โ”œโ”€ Chat
      โ”‚  โ”œโ”€ Error
      โ”‚  โ”œโ”€ FollowerList
      โ”‚  โ”œโ”€ Home
      โ”‚  โ”œโ”€ Loading
      โ”‚  โ”œโ”€ Map
      โ”‚  โ”œโ”€ Post
      โ”‚  โ”œโ”€ Profile
      โ”‚  โ”œโ”€ ProfileSetting
      โ”‚  โ”œโ”€ Search
      โ”‚  โ”œโ”€ Splash
      โ”‚  โ””โ”€ Welcome
      โ””โ”€ routes