๐Ÿก ์ˆ™๋ฐ• ์˜ˆ์•ฝ ํ”Œ๋žซํผ: Kakao Map ์ง€๋„ ์—ฐ๋™๊ณผ ์ƒ์„ธ ํŽ˜์ด์ง€ ๊ตฌํ˜„ (3)

0
post-thumbnail

๋ณธ ๊ธ€์€ ํŒจ์ŠคํŠธ์บ ํผ์Šค โ€“ Next.js ์‹ค๋ฌด ๊ฐ•์˜ ์ค‘ Part 8. Next.js 13์œผ๋กœ ์ˆ™๋ฐ• ์˜ˆ์•ฝ ํ”Œ๋žซํผ ๋งŒ๋“ค๊ธฐ๋ฅผ ์ˆ˜๊ฐ•ํ•˜๋ฉฐ ํ•™์Šตํ•œ ๋‚ด์šฉ์„ ์ •๋ฆฌํ•œ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๐Ÿ™๐Ÿป


๐Ÿ“ ์ˆ™๋ฐ• ์˜ˆ์•ฝ ํ”Œ๋žซํผ ์ง€๋„ ๊ฐœ๋ฐœํ•˜๊ธฐ

โ–ช๏ธ Next Script ์•Œ์•„๋ณด๊ธฐ

next/script๋Š” ์™ธ๋ถ€ ์Šคํฌ๋ฆฝํŠธ๋ฅผ ํŽ˜์ด์ง€์— ํšจ์œจ์ ์œผ๋กœ ์‚ฝ์ž…ํ•  ์ˆ˜ ์žˆ๋„๋ก ๋„์™€์ฃผ๋Š” ์ปดํฌ๋„ŒํŠธ๋‹ค. ๋ธŒ๋ผ์šฐ์ €์—์„œ <script> ํƒœ๊ทธ๋ฅผ ์ˆ˜๋™์œผ๋กœ ์‚ฝ์ž…ํ•˜๋Š” ๊ฒƒ๊ณผ ๋‹ฌ๋ฆฌScript ์ปดํฌ๋„ŒํŠธ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์Šคํฌ๋ฆฝํŠธ์˜ ๋กœ๋”ฉ ์ „๋žต์„ ๋ช…ํ™•ํ•˜๊ฒŒ ์„ค์ •ํ•˜์—ฌ ํŽ˜์ด์ง€ ์„ฑ๋Šฅ๊ณผ ์‹คํ–‰ ์‹œ์ ์„ ํšจ๊ณผ์ ์œผ๋กœ ์ œ์–ดํ•  ์ˆ˜ ์žˆ๋‹ค.

  • Script ์ปดํฌ๋„ŒํŠธ๋Š” SSR(์„œ๋ฒ„ ์‚ฌ์ด๋“œ ๋ Œ๋”๋ง)๊ณผ CSR(ํด๋ผ์ด์–ธํŠธ ์‚ฌ์ด๋“œ ๋ Œ๋”๋ง) ํ™˜๊ฒฝ ๋ชจ๋‘์—์„œ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•˜๋‹ค.
  • ํŽ˜์ด์ง€ ์ง„์ž… ์‹œ ํ•„์š”ํ•œ ์™ธ๋ถ€ ์Šคํฌ๋ฆฝํŠธ๋ฅผ ๋น„๋™๊ธฐ์ ์œผ๋กœ ๋กœ๋“œํ•˜๊ฑฐ๋‚˜, ์ง€์ •๋œ ํƒ€์ด๋ฐ์— ๋งž์ถฐ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ์–ด ์ดˆ๊ธฐํ™” ํ๋ฆ„์„ ์œ ์—ฐํ•˜๊ฒŒ ์ œ์–ดํ•  ์ˆ˜ ์žˆ๋‹ค.

๐Ÿ’ก next/script์˜ ์ฃผ์š” ํŠน์ง•

  • ๋กœ๋”ฉ ์ „๋žต ์ œ์–ด (strategy)
    • beforeInteractive: HTML์ด ๋ Œ๋”๋ง๋˜๊ธฐ ์ „, ํŽ˜์ด์ง€๊ฐ€ interactive ์ƒํƒœ๊ฐ€ ๋˜๊ธฐ ์ด์ „์— ์‹คํ–‰ํ•ด์•ผ ํ•˜๋Š” ์Šคํฌ๋ฆฝํŠธ (ex. A/B ํ…Œ์ŠคํŠธ, ์ดˆ๊ธฐ ์ถ”์  ์Šคํฌ๋ฆฝํŠธ)
    • afterInteractive(๊ธฐ๋ณธ๊ฐ’): HTML ํŒŒ์‹ฑ๊ณผ DOM ๊ตฌ์„ฑ์ด ์™„๋ฃŒ๋˜์–ด ์‚ฌ์šฉ์ž๊ฐ€ ์ธํ„ฐ๋ž™์…˜ ๊ฐ€๋Šฅํ•œ ์‹œ์  ์ดํ›„์— ๋กœ๋“œ๋จ (๊ธฐ๋ณธ๊ฐ’)
    • lazyOnload: ๋ธŒ๋ผ์šฐ์ €์˜ idle ์‹œ๊ฐ„์— ๋กœ๋“œ๋˜์–ด ์ดˆ๊ธฐ ๋ Œ๋”๋ง ์„ฑ๋Šฅ์— ์˜ํ–ฅ์„ ์ฃผ์ง€ ์•Š์Œ (์„ฑ๋Šฅ ์ตœ์ ํ™”์— ์œ ๋ฆฌ, ๋น„ํ•„์ˆ˜ ์Šคํฌ๋ฆฝํŠธ์— ์ ํ•ฉ)
    • worker: Web Worker๋ฅผ ํ†ตํ•ด ๋ฉ”์ธ ์“ฐ๋ ˆ๋“œ์™€ ๋ถ„๋ฆฌ๋œ ํ™˜๊ฒฝ์—์„œ ์‹คํ–‰ (ํ˜„์žฌ experimental ๊ธฐ๋Šฅ)
  • ์ž๋™ ์ตœ์ ํ™” ๊ธฐ๋Šฅ ๋‚ด์žฅ : ์ค‘๋ณต ๋กœ๋“œ ๋ฐฉ์ง€, ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ, ๋ Œ๋”๋ง ์ฐจ๋‹จ ๋ฐฉ์ง€ ๋“ฑ์˜ ์„ฑ๋Šฅ ์ตœ์ ํ™” ๊ธฐ๋Šฅ์ด ๋‚ด์žฅ

๐Ÿ’ก next/script ์ฃผ์š” ์†์„ฑ (Props)

  • src ๋กœ๋“œํ•  ์Šคํฌ๋ฆฝํŠธ์˜ URL ๋˜๋Š” ๊ฒฝ๋กœ ์ง€์ •
  • strategy ์Šคํฌ๋ฆฝํŠธ์˜ ๋กœ๋”ฉ ์ „๋žต ์„ค์ •
    (์–ธ์ œ ๋กœ๋“œ ๋ฐ ์‹คํ–‰ํ• ์ง€๋ฅผ ๊ฒฐ์ •, beforeInteractive, afterInteractive, lazyOnload, worker ์ค‘ ์„ ํƒ)
  • onLoad ์Šคํฌ๋ฆฝํŠธ๊ฐ€ ์„ฑ๊ณต์ ์œผ๋กœ ๋กœ๋“œ๋œ ํ›„ ์‹คํ–‰ํ•  ์ฝœ๋ฐฑ ํ•จ์ˆ˜๋ฅผ ์ง€์ •
  • onReady ์Šคํฌ๋ฆฝํŠธ๊ฐ€ ์ค€๋น„๋˜์—ˆ์„ ๋•Œ ์‹คํ–‰ํ•  ์ฝœ๋ฐฑ ํ•จ์ˆ˜๋ฅผ ์ง€์ •
    (๋ธŒ๋ผ์šฐ์ €๊ฐ€ ์ด๋ฏธ ํ•ด๋‹น ์Šคํฌ๋ฆฝํŠธ๋ฅผ ์บ์‹œ์— ๊ฐ€์ง€๊ณ  ์žˆ๋Š” ๊ฒฝ์šฐ ์œ ์šฉ)
  • onError ์Šคํฌ๋ฆฝํŠธ ๋กœ๋”ฉ ์ค‘ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ–ˆ์„ ๋•Œ ์‹คํ–‰ํ•  ์ฝœ๋ฐฑ ํ•จ์ˆ˜๋ฅผ ์ง€์ •

onLoad์™€ onReady์˜ ์ฐจ์ด ๐Ÿค”

  • onLoad: ์Šคํฌ๋ฆฝํŠธ๊ฐ€ ๋„คํŠธ์›Œํฌ๋ฅผ ํ†ตํ•ด ์ฒ˜์Œ ๋กœ๋“œ๋  ๋•Œ๋งŒ ์‹คํ–‰ (strategy="beforeInteractive"์™€๋Š” ํ•จ๊ป˜ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†์Œ)
  • onReady: ์Šคํฌ๋ฆฝํŠธ๊ฐ€ ์ด๋ฏธ ๋กœ๋“œ๋œ ์ƒํƒœ์—์„œ๋„ ํ•ญ์ƒ ์‹คํ–‰ (์ดˆ๊ธฐํ™” ์ดํ›„์˜ ํ›„์† ์ž‘์—… ex. ์ง€๋„ ๋ Œ๋”๋ง, ์œ„์ ฏ ์‹คํ–‰ ๋“ฑ)์— ์ ํ•ฉ

โ–ช๏ธ Kakao Map API ์ง€๋„ ์ปดํฌ๋„ŒํŠธ ์—ฐ๋™ํ•˜๊ธฐ

  1. Kakao Developers ์„ธํŒ…
    ์นด์นด์˜ค ๋””๋ฒจ๋กœํผ์Šค์—์„œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ์ƒ์„ฑํ•œ ํ›„, ์•ฑ ํ‚ค ์„ค์ •์—์„œ ์ œ๊ณต๋˜๋Š” JavaScript ํ‚ค๋ฅผ ๋ณต์‚ฌํ•˜์—ฌ ํ”„๋กœ์ ํŠธ์˜ ํ™˜๊ฒฝ ๋ณ€์ˆ˜์— ์ €์žฅํ•œ๋‹ค. API ์‚ฌ์šฉ์„ ์œ„ํ•ด ํ”Œ๋žซํผ ์„ค์ •(web) ํ•ญ๋ชฉ์— ๋กœ์ปฌ ๊ฐœ๋ฐœ ํ™˜๊ฒฝ ์ฃผ์†Œ(http://localhost:3000)๋ฅผ ๋“ฑ๋ก์ด ํ•„์š”ํ•˜๋‹ค.
    (์ฐธ๊ณ ) Kakao Map API๋ฅผ ์ •์ƒ์ ์œผ๋กœ ์‚ฌ์šฉํ•˜๋ ค๋ฉด ์ œํ’ˆ ์„ค์ • - ์นด์นด์˜ค๋งต ์‚ฌ์šฉ ์„ค์ • ํ™œ์„ฑํ™”๋ฅผ ๊ผญ ์ง„ํ–‰ํ•ด์•ผ ํ•œ๋‹ค. ํ•ด๋‹น API๊ฐ€ ํ™œ์„ฑํ™”๋˜์–ด ์žˆ์ง€ ์•Š์œผ๋ฉด ์ง€๋„ ์š”์ฒญ ์‹œ 403 ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•˜๋ฏ€๋กœ ์„ค์ •์—์„œ ๋ฐ˜๋“œ์‹œ ํ™œ์„ฑํ™”ํ•  ๊ฒƒ! ๐Ÿคช

  1. Kakao Map API ์ง€๋„ ๋ถˆ๋Ÿฌ์˜ค๊ธฐ
    next/script ์ปดํฌ๋„ŒํŠธ๋ฅผ ์‚ฌ์šฉํ•ด Kakao Maps JavaScript SDK๋ฅผ ๋™์ ์œผ๋กœ ๋กœ๋“œํ–ˆ๋‹ค. ์Šคํฌ๋ฆฝํŠธ๋Š” strategy="afterInteractive"๋กœ ์„ค์ •ํ•ด ํŽ˜์ด์ง€๊ฐ€ interactive ์ƒํƒœ๊ฐ€ ๋œ ์ดํ›„์— ๋กœ๋“œ๋˜๋„๋ก ํ–ˆ๊ณ  SDK ๋กœ๋“œ ์™„๋ฃŒ ์‹œ์ ์„ onReady ์ฝœ๋ฐฑ์—์„œ ๊ฐ์ง€ํ–ˆ๋‹ค.
    onReady ์ฝœ๋ฐฑ ๋‚ด๋ถ€์—์„œ๋Š” kakao.maps.load() ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•ด ์ง€๋„๋ฅผ ์ดˆ๊ธฐํ™”ํ–ˆ๋‹ค. ์ด ๋ฉ”์„œ๋“œ๋Š” Kakao์—์„œ ์ œ๊ณตํ•˜๋Š” ๊ณต์‹ ๋ฐฉ์‹์œผ๋กœ SDK๊ฐ€ ์™„์ „ํžˆ ๋กœ๋“œ๋œ ์ดํ›„ ์•ˆ์ „ํ•˜๊ฒŒ kakao ๊ฐ์ฒด๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ๋ณด์žฅํ•ด์ค€๋‹ค.
    TypeScript ๋ฐ ESLint ํ™˜๊ฒฝ์—์„œ๋Š” ์ „์—ญ ๊ฐ์ฒด์ธ kakao๊ฐ€ ์ •์˜๋˜์ง€ ์•Š์•˜๋‹ค๋Š” ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋‹ค. ์ด๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด, ์Šคํฌ๋ฆฝํŠธ ์ƒ๋‹จ์— /* global kakao */ ์ฃผ์„์„ ์ถ”๊ฐ€ํ•˜์—ฌ ESLint๊ฐ€ kakao๋ฅผ ๊ธ€๋กœ๋ฒŒ ๋ณ€์ˆ˜๋กœ ์ธ์‹ํ•˜๋„๋ก ์ฒ˜๋ฆฌ๊ฐ€ ํ•„์š”ํ•˜๋‹ค.

Kakao Developers - ์นด์นด์˜ค
Kakao ์ง€๋„ Web API Documentation
Kakao ์ง€๋„ Web API Documentation - load


โ–ช๏ธ Kakao Map์œผ๋กœ ๊ธฐ๋ณธ ๋งˆ์ปค ๊ตฌํ˜„ํ•˜๊ธฐ

Kakao ์ง€๋„ Web API Documentation - basicMarker

useQuery๋ฅผ ์‚ฌ์šฉํ•ด /api/rooms์—์„œ ๋ชจ๋“  ์ˆ™์†Œ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ค๊ณ  loadKakaoMap ํ•จ์ˆ˜ ๋‚ด๋ถ€์—์„œ ํ•ด๋‹น ๋ฐ์ดํ„ฐ๋ฅผ ์ˆœํšŒํ•˜๋ฉฐ ๊ฐ ์ˆ™์†Œ ์œ„์น˜์— ๊ธฐ๋ณธ ๋งˆ์ปค๋ฅผ ํ‘œ์‹œํ•˜๋„๋ก ๊ตฌํ˜„ํ–ˆ๋‹ค.


โ–ช๏ธ Kakao Map์œผ๋กœ ์ปค์Šคํ…€ ๋งˆ์ปค ๊ตฌํ˜„ํ•˜๊ธฐ

Kakao ์ง€๋„ Web API Documentation - ๋‹ค๋ฅธ ์ด๋ฏธ์ง€๋กœ ๋งˆ์ปค ์ƒ์„ฑํ•˜๊ธฐ
Kakao ์ง€๋„ Web API Documentation - ์ปค์Šคํ…€ ์˜ค๋ฒ„๋ ˆ์ด ์ƒ์„ฑํ•˜๊ธฐ

Kakao Map API์˜ MarkerImage๋ฅผ ํ™œ์šฉํ•ด ๊ธฐ๋ณธ ๋งˆ์ปค ๋Œ€์‹  ์ปค์Šคํ…€ ์ด๋ฏธ์ง€๋ฅผ ์ ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. ๋งˆ์ปค ์ด๋ฏธ์ง€์˜ ํฌ๊ธฐ์™€ ๊ธฐ์ค€์ (offset) ์„ ํ•จ๊ป˜ ์„ค์ •ํ•ด ๊ตฌ์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค.

CustomOverlay๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋งˆ์ปค ๋Œ€์‹  ์ง€๋„ ์œ„์— ์‚ฌ์šฉ์ž ์ •์˜ ๋งˆํฌ์—…๋„ ์‚ฝ์ž…ํ•  ์ˆ˜ ์žˆ๋‹ค.
์ด๋ฅผ ํ™œ์šฉํ•ด ์ˆ™์†Œ์˜ ๊ฐ€๊ฒฉ ์ •๋ณด๋ฅผ ์ปค์Šคํ…€ ์˜ค๋ฒ„๋ ˆ์ด ํ˜•ํƒœ๋กœ ์ง€๋„์— ํ•จ๊ป˜ ํ‘œ์‹œํ•˜๋„๋ก ์„ค์ •ํ–ˆ๋‹ค.

์ด๋•Œ ์˜ค๋ฒ„๋ ˆ์ด์— ๋“ค์–ด๊ฐˆ ๊ฐ€๊ฒฉ ์ •๋ณด์— ์Šคํƒ€์ผ์„ ์ ์šฉํ•˜๊ธฐ ์œ„ํ•ด Tailwind์˜ @apply ์ง€์‹œ์–ด๋ฅผ ํ™œ์šฉํ•ด ์œ ํ‹ธ๋ฆฌํ‹ฐ ํด๋ž˜์Šค๋“ค์„ .custom_overlay ํด๋ž˜์Šค๋กœ ๋ฌถ์–ด HTML์— ์ ์šฉํ–ˆ๋‹ค.

 // custom overlay๋ฅผ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค.
 const content = `<div class="custom_overlay">${data.price?.toLocaleString()}์›</div>`
/* global.css */
.custom_overlay {
  @apply bg-white rounded-full px-2 py-1 text-xs font-semibold border border-gray-300 shadow hover:shadow-lg hover:font-bold;
}

โ–ช๏ธ next/image๋กœ ์ด๋ฏธ์ง€ ๋ Œ๋”๋ง ๋ฐฉ์‹ ๊ฐœ์„ 

Next.js - Image Optimization

๋ฉ”์ธ ํŽ˜์ด์ง€์—์„œ ์ˆ™์†Œ ๋ฐ์ดํ„ฐ๋ฅผ ๋ Œ๋”๋งํ•  ๋•Œ ์ด๋ฏธ์ง€๊ฐ€ ๋กœ๋“œ๋˜๊ธฐ ์ „๊นŒ์ง€ ๊ณต๊ฐ„์ด ํ™•๋ณด๋˜์ง€ ์•Š์•„ ๋ ˆ์ด์•„์›ƒ ์‰ฌํ”„ํŠธ(Layout Shift)๊ฐ€ ๋ฐœ์ƒํ•˜๋Š” ๋ฌธ์ œ๊ฐ€ ์žˆ๋‹ค.

์ด๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด Next.js์˜ next/image ์ปดํฌ๋„ŒํŠธ๋กœ ๋ณ€๊ฒฝํ–ˆ๋‹ค. next/image๋Š” ์ด๋ฏธ์ง€ ํฌ๊ธฐ๋ฅผ ๋ฏธ๋ฆฌ ๊ณ„์‚ฐํ•˜์—ฌ ๊ณต๊ฐ„์„ ํ™•๋ณดํ•ด์ฃผ๊ธฐ ๋•Œ๋ฌธ์— ๋ Œ๋”๋ง ์ค‘ ๋ฐœ์ƒํ•˜๋Š” ๋ ˆ์ด์•„์›ƒ ๋ณ€๊ฒฝ ์—†์ด ์•ˆ์ •์ ์ธ UI๋ฅผ ์œ ์ง€ํ•  ์ˆ˜ ์žˆ๋‹ค.

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

  • next/image ์ปดํฌ๋„ŒํŠธ๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ ์™ธ๋ถ€ ์ด๋ฏธ์ง€ ๋„๋ฉ”์ธ์„ ๋กœ๋“œํ•˜๋ ค๋ฉด ํ•ด๋‹น ์ด๋ฏธ์ง€์˜ ํ˜ธ์ŠคํŠธ๋ช…(hostname) ์„ next.config.js์˜ images.domains ์„ค์ •์— ๋ช…์‹œํ•ด์•ผ ํ•œ๋‹ค. ์ด ์„ค์ •์ด ๋ˆ„๋ฝ๋˜๋ฉด ์ด๋ฏธ์ง€ ์ตœ์ ํ™”๊ฐ€ ์ ์šฉ๋˜์ง€ ์•Š๊ฑฐ๋‚˜ ๋กœ๋”ฉ์ด ์ฐจ๋‹จ๋  ์ˆ˜ ์žˆ๋‹ค.

์ ์šฉ ์ „ํ›„ ์ฐจ์ด ๐Ÿ‘€


์ ์šฉ ํ›„ ๐Ÿคฉ

โ–ช๏ธ ์„ ํƒํ•œ ์ˆ™์†Œ UI ์ปดํฌ๋„ŒํŠธ ๊ตฌํ˜„ํ•˜๊ธฐ

Kakao ์ง€๋„ Web API Documentation - ํด๋ฆญ ์ด๋ฒคํŠธ ๋“ฑ๋กํ•˜๊ธฐ

๋งˆ์ปค ํด๋ฆญ ์‹œ window.kakao.maps.event.addListener๋ฅผ ํ†ตํ•ด ์ด๋ฒคํŠธ๋ฅผ ๋“ฑ๋กํ•˜๊ณ  ์„ ํƒ๋œ ์ˆ™์†Œ ๋ฐ์ดํ„ฐ๋ฅผ Recoil ์ „์—ญ ์ƒํƒœ์— ์ €์žฅํ•ด ์ƒ์„ธ ์ •๋ณด UI์™€ ์—ฐ๋™ํ–ˆ๋‹ค. ์ง€๋„ ๋‚ด ๋นˆ ์˜์—ญ์„ ํด๋ฆญํ•˜๋ฉด ํ•ด๋‹น ์ƒํƒœ๋ฅผ ์ดˆ๊ธฐํ™”ํ•ด ์ƒ์„ธ ์ •๋ณด๊ฐ€ ๋…ธ์ถœ๋˜์ง€ ์•Š๋„๋ก ์ฒ˜๋ฆฌํ–ˆ๋‹ค.


๐Ÿ  ์ˆ™์†Œ ์ƒ์„ธ ํŽ˜์ด์ง€ ๊ฐœ๋ฐœํ•˜๊ธฐ

โ–ช๏ธ ์ˆ™์†Œ ์ƒ์„ธ ํŽ˜์ด์ง€ UI ๊ฐœ๋ฐœํ•˜๊ธฐ

๋ฉ”์ธ ํ™”๋ฉด์—์„œ ์ˆ™์†Œ๋ฅผ ํด๋ฆญํ•˜๋ฉด ํ•ด๋‹น ์ˆ™์†Œ์˜ id ๊ฐ’์„ ํ†ตํ•ด ์ƒ์„ธ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ค๊ณ , ์ด๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ๊ฐ ์˜์—ญ์— ๋ฐ์ดํ„ฐ๋ฅผ ์—ฐ๋™ํ•˜๋„๋ก ๊ตฌํ˜„ํ–ˆ๋‹ค. ๊ธฐ์กด์—๋Š” ๋ฌดํ•œ ์Šคํฌ๋กค์„ ํ†ตํ•ด ๋ชฉ๋ก ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ›์•„์˜ค๋Š” ๊ตฌ์กฐ์˜€๊ธฐ ๋•Œ๋ฌธ์— ๋‹จ์ผ ์ˆ™์†Œ์˜ ์ƒ์„ธ ๋ฐ์ดํ„ฐ๋ฅผ ๋ถˆ๋Ÿฌ์˜ค๋Š” ์กฐ๊ฑด์„ ๋ถ„๊ธฐํ•˜์—ฌ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋„๋ก ์ธํ„ฐํŽ˜์ด์Šค์™€ ์กฐ๊ฑด๋ฌธ์„ ๋ณด์™„ํ–ˆ๋‹ค.

์ˆ™์†Œ ์ƒ์„ธ ์ •๋ณด ํŽ˜์ด์ง€๋Š” ์ƒ๋‹จ์˜ ์ด๋ฏธ์ง€, ์ขŒ์ธก์˜ ์ƒ์„ธ ๋‚ด์šฉ๊ณผ ์šฐ์ธก ์˜ˆ์•ฝ ๋ฐฐ๋„ˆ ์ปดํฌ๋„ŒํŠธ๋กœ ๋‚˜๋ˆ„์–ด UI๋ฅผ ๊ตฌ์„ฑํ–ˆ๋‹ค.

์ˆ™์†Œ์˜ ๋ถ€๊ฐ€ ๊ธฐ๋Šฅ(์˜ˆ: ์…€ํ”„ ์ฒดํฌ์ธ ๊ฐ€๋Šฅ ์—ฌ๋ถ€, ์‚ฌ๋ฌด ๊ณต๊ฐ„ ์ œ๊ณต ๋“ฑ)์„ ์‚ฌ์šฉ์ž์—๊ฒŒ ์•ˆ๋‚ดํ•˜๊ธฐ ์œ„ํ•ด ๊ธฐ๋Šฅ ํƒ€์ž…๊ณผ ์„ค๋ช… ๋ฌธ๊ตฌ๋ฅผ ๋งคํ•‘ํ•˜๋Š” ๊ตฌ์กฐ๋ฅผ ์„ค๊ณ„ํ–ˆ๋‹ค.

FEATURE_TYPE ์ƒ์ˆ˜๋ฅผ Enum์ฒ˜๋Ÿผ ์ •์˜ํ•˜๊ณ  ๊ฐ ํ‚ค์— ๋Œ€ํ•œ ์„ค๋ช…์€ FeatureDesc ๊ฐ์ฒด์— ๋งคํ•‘ํ–ˆ๋‹ค.
์ด ๋ฐฉ์‹์€ ์กฐ๊ฑด๋ฌธ ์—†์ด๋„ ๊ธฐ๋Šฅ ํ‚ค๋งŒ ๋„˜๊ฒจ ๊ฐ„๊ฒฐํ•˜๊ฒŒ ์„ค๋ช…์„ ์ถœ๋ ฅํ•  ์ˆ˜ ์žˆ์–ด ์œ ์ง€๋ณด์ˆ˜์— ์šฉ์ดํ•˜๋‹ค.

const FEATURE_TYPE = {
  FREE_CANCEL: 'FREE_CANCEL',
  SELF_CHECKIN: 'SELF_CHECKIN',
  FREE_OFFICE_SPACE: 'FREE_OFFICE_SPACE',
} as const

type FeatureType = (typeof FEATURE_TYPE)[keyof typeof FEATURE_TYPE]

export const FeatureDesc: Record<FeatureType, string> = {
  [FEATURE_TYPE.FREE_CANCEL]: '๋ฌด๋ฃŒ ์ทจ์†Œ๊ฐ€ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.',
  [FEATURE_TYPE.SELF_CHECKIN]: '์…€ํ”„ ์ฒดํฌ์ธ์ด ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.',
  [FEATURE_TYPE.FREE_OFFICE_SPACE]: '์‚ฌ๋ฌด ์‹œ์„ค์ด ์žˆ์Šต๋‹ˆ๋‹ค.',
}

โ–ช๏ธ ์ˆ™๋ฐ• ์ƒ์„ธ ํŽ˜์ด์ง€ ์ง€๋„ ์ปจํŠธ๋กค ์ถ”๊ฐ€

Kakao ์ง€๋„ Web API Documentation - ์ง€๋„์— ์ปจํŠธ๋กค ์˜ฌ๋ฆฌ๊ธฐ

๊ธฐ์กด ์ง€๋„ ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ˆ˜์ •ํ•ด ๋‹จ์ผ ์ˆ™์†Œ๋งŒ ๋งˆ์ปค๋กœ ํ‘œ์‹œ๋˜๋„๋ก ํ•˜๊ณ  Kakao Map ๋ฌธ์„œ๋ฅผ ์ฐธ๊ณ ํ•ด ์ง€๋„ ์ปจํŠธ๋กค ๊ธฐ๋Šฅ๋„ ๊ฐ„๋‹จํžˆ ์ถ”๊ฐ€ํ–ˆ๋‹ค. ๐Ÿคฉ ( ํ…Œ์ŠคํŠธ๋กœ ๋„ฃ์€ ๋ฐ์ดํ„ฐ๊ฐ€ ๋งˆ์นจ ํ•œ๊ฐ• ์œ„์—.. ) ๐Ÿคช


โ–ช๏ธ ์ˆ™๋ฐ• ์ƒ์„ธ ํŽ˜์ด์ง€ ๊ณต์œ ํ•˜๊ธฐ ๋ฒ„ํŠผ ๊ธฐ๋Šฅ ๊ตฌํ˜„ํ•˜๊ธฐ

Headless UI
react-hot-toast

์ฒ˜์Œ ์‚ฌ์šฉํ•ด๋ณธ Headless UI๋ฅผ ํ™œ์šฉํ•ด ์ ‘๊ทผ์„ฑ ๋†’์€ ๊ณต์œ  ๋ชจ๋‹ฌ์„ ๊ฐ„ํŽธํ•˜๊ฒŒ ๊ตฌํ˜„ํ–ˆ๋‹ค.Dialog, Transition, DialogPanel ์ปดํฌ๋„ŒํŠธ๋ฅผ ์กฐํ•ฉํ•˜๊ณ  useState๋ฅผ ํ†ตํ•ด ์—ด๋ฆผ/๋‹ซํž˜ ์ƒํƒœ๋ฅผ ์ œ์–ดํ–ˆ๋‹ค.

๋ชจ๋‹ฌ์—๋Š” ๊ณต์œ  ๋Œ€์ƒ ์ˆ™์†Œ์˜ ๋Œ€ํ‘œ ์ด๋ฏธ์ง€, ์ˆ™์†Œ๋ช…, ์นดํ…Œ๊ณ ๋ฆฌ, ์ฃผ์†Œ ๋“ฑ์˜ ์ •๋ณด๋ฅผ ๊ฐ„๋‹จํžˆ ํ‘œ์‹œํ•˜๊ณ , ์•„๋ž˜์™€ ๊ฐ™์€ ๊ณต์œ  ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ–ˆ๋‹ค.

๋งํฌ ๋ณต์‚ฌ ๋ฐ SNS ๊ณต์œ  ๊ธฐ๋Šฅ

  • ๋งํฌ ๋ณต์‚ฌ: navigator.clipboard.writeText() ํด๋ฆฝ๋ณด๋“œ API๋ฅผ ์‚ฌ์šฉํ•ด ํ˜„์žฌ ํŽ˜์ด์ง€ URL์„ ๋ณต์‚ฌํ•˜๊ณ  ์„ฑ๊ณต/์‹คํŒจ ์—ฌ๋ถ€์— ๋”ฐ๋ผ react-hot-toast๋ฅผ ํ†ตํ•ด ํ”ผ๋“œ๋ฐฑ ๋ฉ”์‹œ์ง€๋ฅผ ํ‘œ์‹œ
  • ์ด๋ฉ”์ผ ๊ณต์œ : mailto: ํ”„๋กœํ† ์ฝœ์„ ํ™œ์šฉํ•ด ๊ธฐ๋ณธ ๋ฉ”์ผ ์•ฑ(Gmail, Apple Mail ๋“ฑ)์ด ์‹คํ–‰๋  ์ˆ˜ ์žˆ๋„๋กํ•˜์˜€๊ณ  subject์—๋Š” ์ด๋ฉ”์ผ ์ œ๋ชฉ, body์—๋Š” ๊ณต์œ ํ•  ์ˆ™์†Œ URL์ด ์ž๋™์œผ๋กœ ์‚ฝ์ž…๋˜๋„๋ก ์ถ”๊ฐ€
  • ํŠธ์œ„ํ„ฐ ๊ณต์œ : https://www.twitter.com/intent/tweet?url=${window.location.href} URL๋กœ window.open()์„ ์‚ฌ์šฉํ•ด SNS ๊ณต์œ ์šฉ ์ƒˆ ํƒญ์„ ์—ด๋„๋ก ๊ตฌ์„ฑ
  • ํŽ˜์ด์Šค๋ถ ๊ณต์œ : https://www.facebook.com/sharer/sharer.php?u=${window.location.href} (ํŠธ์œ„ํ„ฐ์™€ ๋™์ผ)

profile
์ฐจ๊ณก์ฐจ๊ณก ์Œ“์•„๋‘๊ธฐ ๐Ÿ’ญ

0๊ฐœ์˜ ๋Œ“๊ธ€