์บ ํํ ํ๋ก์ ํธ์์ ์นด์นด์ค API๋ก ์ง๋ ๊ตฌํ์ ํ๋ค !
์ง๋ ํ์ด์ง์์๋ ๋ ๊ฐ์ง ๊ฒ์์ด ๊ฐ๋ฅํ ๋ฐ,
Nav ๋ฐ๋ฅผ ํตํด ์ ๊ทผํ๋ฉด ๋จผ์ ์ ์ ์ ์์น๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ํ ์บ ํ์ฅ์ด ๊ฒ์๋๋ค.
๋ ๋ฒ์งธ๋ก ๊ฒ์๋ฐ๋ฅผ ํตํด ์ง์ญ์ ๊ฒ์ํ๋ฉด ํด๋น ์ง์ญ์ ์์นํ ์บ ํ์ฅ์ด ๊ฒ์๋๋ค.
๋จผ์ ๋ง์ปค๋ก ์ง๋์ ์บ ํ์ฅ๋ค์ ์ฐ์ด์ฃผ๋ ๊ตฌํ๋ง ํ๋ค.
next.js์ Script
ํ๊ทธ๋ฅผ ์ฌ์ฉํด ์คํฌ๋ฆฝํธ๋ฅผ ํฌํจ์์ผ์ฃผ๊ณ ,
beforeInteractive
๋ฅผ ์ฌ์ฉํ์ฌ ํ์ด์ง ๋ ๋๋ง ์ ์ ์คํฌ๋ฆฝํธ๋ฅผ ๋ก๋ํ๋๋ก ํ์ฌ ๋ก๋ฉ ์๋๋ฅผ ํฅ์์์ผฐ๋ค.
autoload=false
๋ฅผ ํตํด ์นด์นด์ค ๋งต SDK๊ฐ ์๋์ผ๋ก ๋ก๋๋์ง ์๋๋ก ํด์ ์คํฌ๋ฆฝํธ ๋ก๋ ํ ํ์ ์์ ์
๋งต์ ์ด๊ธฐํ ํ ์ ์๋๋ก ํจ์ผ๋ก์จ ๋งต ๋ก๋ฉ์ ์ ์ดํ ์ ์๋๋ก ํ๋ค.
๋ libraries=clusterer
๋ฅผ ํตํด ํด๋ฌ์คํฐ๋ง ๊ธฐ๋ฅ์ ํจ๊ป ๋ก๋ํ๋ค.
<Script
strategy="beforeInteractive"
src={`https://dapi.kakao.com/v2/maps/sdk.js?appkey=${process.env.NEXT_PUBLIC_KAKAO_MAP_KEY}&autoload=false&libraries=clusterer`}
/>
๐ก Kakao Map Script ์ต์ ํ
beforeInteractive
: ํ์ด์ง ๋ ๋๋ง ์ ์ ์คํฌ๋ฆฝํธ ๋ก๋ํ์ฌ ํ์ด์ง ๋ ๋๋ง ์๋ ์ต์ ํautoload=false
: ์นด์นด์ค ๋งต์ด ์๋์ผ๋ก ๋ก๋๋์ง ์๋๋ก ์ค์ ํ์ฌ ๋งต ๋ก๋ฉ ์ ์ด ๊ฐ๋ฅ
useEffect(() => {
if (!kakaoMap || campList?.length === 0) return;
const positions = campList.map((camp) => ({
id: camp.contentId,
title: camp.facltNm,
latlng: new window.kakao.maps.LatLng(
camp.location.coordinates[1],
camp.location.coordinates[0]
),
address: camp.addr1,
imgSrc: camp.firstImageUrl,
}));
positions.forEach((position) => {
const marker = new window.kakao.maps.Marker({
map: kakaoMap,
position: position.latlng,
title: position.title,
address: position.address,
contentId: position.id,
});
marker.setMap(kakaoMap);
});
}, [campList, kakaoMap]);
์์ ๊ฐ์ด ๋ฐ์ดํฐ์ ์๋ ์บ ํ์ฅ ๋ฆฌ์คํธ๋ฅผ ๊ฐ์ง๊ณ ์ง๋์ ๋ง์ปค๋ฅผ ํ์ํ ์ ์๋ค.
ํ์ง๋ง... ์ง์ญ ๊ฒ์ ์ '๊ฒฝ๊ธฐ๋'์ ๊ฐ์ด ๋ง์ ์์ ์บ ํ์ฅ์ด ์๋ ๊ณณ์ ๊ฒฝ์ฐ
์ง๋ ๋ก๋ฉ ๋ฐ ๋ ๋๋ง ์๋์ ์ง๋๋ฅผ ํ๋/์ถ์ํ๊ฑฐ๋ ์ด๋ํ ๋ ๊ณผ๋ํ ์ฐ์ฐ์ผ๋ก ์ธํด ํ๋ฉด์ด ๋ฉ์ถ๋ ํ์์ด ๋ฐ์ํ๋ค.
์ด๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด ํ๋ฉด์ ๋ง์ปค๋ฅผ ์ค์ด๊ณ ๊ทธ๋ฃน์ผ๋ก ๋ฌถ์ด ์ฃผ๊ธฐ ์ํด
์นด์นด์ค ์ง๋์ ํด๋ฌ์คํฐ๋ฌ( clusterer )๋ฅผ ์ ์ฉํ๊ธฐ๋ก ํ๋ค.
useEffect(() => {
// ์ง๋ ๊ฐ์ฒด, ์บ ํ์ฅ ๋ชฉ๋ก์ด ์์ผ๋ฉด ํจ์๋ฅผ ์ข
๋ฃํ์ฌ ๋ถํ์ํ ์ฐ์ฐ ๋ฐฉ์ง
if (!kakaoMap || campList?.length === 0) return;
// ์บ ํ์ฅ ์์น ๋ฐ์ดํฐ ๋ณํ ๋ฐ ์ค๋ฒ๋ ์ด ํ์์ ํ์ํ ๋ฐ์ดํฐ ์ ์ฅ
const positions = campList?.map((camp) => ({
id: camp.contentId,
title: camp.facltNm,
latlng: new window.kakao.maps.LatLng(
camp.location.coordinates[1],
camp.location.coordinates[0]
),
address: camp.addr1,
imgSrc: camp.firstImageUrl,
}));
// ๋ง์ปค ๊ฐ์ฒด ์์ฑ: ์ง๋์ ์ถ๊ฐํ์ง ์๊ณ markders ๋ฐฐ์ด์ ์ ์ฅ !
// ํด๋ฌ์คํฐ๋ง์ ์ฌ์ฉํ๊ธฐ ์ํด ์ ์ฅํ๋ ๊ฒ
const markers = positions.map(function (position) {
return new window.kakao.maps.Marker({
position: position.latlng,
});
});
// ๋ง์ปค ํด๋ฌ์คํฐ๋ฌ ์์ฑ
const clusterer = new window.kakao.maps.MarkerClusterer({
map: kakaoMap,
averageCenter: true, // ํด๋ฌ์คํฐ์ ์ค์ฌ์ ์ ๋ง์ปค ํ๊ท ์์น๋ก ์ง์
minLevel: 9, // ์ค ๋ ๋ฒจ์ด 9 ์ดํ์ผ ๋ ํด๋ฌ์คํฐ๋ง ์ ์ฉ
markers: markers, // ์์ฑํ ๋ง์ปค ๋ฆฌ์คํธ ์ถ๊ฐ
});
// ๊ธฐ์กด ๋ง์ปค ์ด๊ธฐํ
markers.forEach((marker) => marker.setMap(null));
// ํด๋ฌ์คํฐ๋ง ์ ๋ณด ์ด๊ธฐํ
clusterer.clear();
// ํด๋ฌ์คํฐ๋ง์ด ์ ์์ ์ผ๋ก ๊ฐฑ์ ๋์ง ์๋ ๋ฒ๊ทธ ๋ฐฉ์ง๋ฅผ ์ํด 100ms ํ ๊ฐ์ ๊ฐฑ์
setTimeout(() => clusterer.redraw(), 100);
positions?.forEach((position) => {
const marker = new window.kakao.maps.Marker({
map: kakaoMap,
position: position.latlng,
title: position.title,
address: position.address,
contentId: position.id,
});
// ํด๋ฌ์คํฐ๋ฌ์ ๋ง์ปค ์ถ๊ฐ
clusterer.addMarker(marker);
// ์ง๋์ ๋ง์ปค ์ถ๊ฐ
marker.setMap(kakaoMap);
setKakaoMarker(marker);
});
}, [campList, kakaoMap]);
์ฌ๋ฌ ๊ฐ์ ๋ง์ปค๊ฐ ๊ฐ๊น์ด ์์ ๊ฒฝ์ฐ ํด๋ฌ์คํฐ๋ง ๋์ด ๋ง์ปค๋ค์ด ๊ทธ๋ฃนํ ๋์ด ๋ ๋๋ง๋๋ค.
๋ถํ์ํ ์ฐ์ฐ์ด ์ค์ด๋ค์ด์ ๋ ๋๋ง ์๋๋ ํจ์ฌ ๋นจ๋ผ์ง๊ณ ๋ฉ์ถ๋ ํ์๋ ์์ด์ก๋ค !
์๊ฐ์ ์ผ๋ก๋ ์ ๋ณด๊ฐ ํจ์ฌ ๋์ ์ ๋ค์ด์ค๊ณ ํ์
ํ๊ธฐ ์ฌ์์ก๋ค.