얼마 전 회사에서 지도 API를 사용할 일이 생겼다.
개인 프로젝트를 진행할 때도 카카오 지도를 써본 터라 이번에도 카카오 지도를 골랐는데 그때에도 지금에도 굉장히 불편함을 느낀 부분이 있었다.
바로 페이지를 이동할 때마다 지도 API와 관련된 스크립트를 다운받는다는 것이다.
심지어 다른 라이브러리를 써야한다면 사진과 같이 drawing, clusterer, services 등의 라이브러리도 페이지를 이동할 때마다 같이 다운받는다.
이러한 점이 정말 불필요하다고 생각했고 지도를 사용하는 페이지를 들어갈 때에만 지도와 관련된 스크립트 파일을 다운받도록 수정하고 싶었다.
Next.js를 사용하고 있었기 때문에 기존의 방법에서는 아래 스크립트 태그를 _document.js
에 삽입해 사용하고 있었다.
<script type="text/javascript" src="//dapi.kakao.com/v2/maps/sdk.js?appkey=발급받은 APP KEY를 넣으시면 됩니다."></script>
그렇기 때문에 페이지를 이동할 때마다 해당 스크립트를 다운받고 있던 것이다.
export default function TestPage() {
return (
<>
<script
type="text/javascript"
src={`//dapi.kakao.com/v2/maps/sdk.js?appkey=${process.env.NEXT_PUBLIC_KAKAO_JAVASCRIPT_KEY}&libraries=services,clusterer,drawing`}
/>
<Map />
</>
);
}
그래서 지도를 사용하는 페이지에 스크립트를 심어보았다.
kakao maps web api 가이드에서도 api를 로딩하는 스크립트 태그는 어느 곳에나 와도 상관없다고 했기 때문이다.
하지만 중요한 점은 바로 아래에 있었다.
API를 로딩하는 스크립트 태그는 HTML파일안의 head, body 등 어떠한 위치에 넣어도 상관없습니다.
하지만, 반드시 실행 코드보다 먼저 선언되어야 합니다.
반드시 실행 코드보다 먼저 선언되어야 한다는 것이 볼드 처리된 이유가 있었다.
스크립트를 다운 받는 것보다 코드가 먼저 실행되기 때문에 런타임 에러가 발생한다.
이는 Next.js에서 제공하는 Script 태그를 써도 동일하다.
++ 혹시나 해서 Next.js에서 제공하는 Head 안에 script를 넣어도 에러가 발생했다.
const mapScript = document && document.createElement('script');
useEffect(() => {
// kakao map script 세팅
if (!document.getElementById('map')) {
mapScript.id = 'map';
mapScript.async = true;
mapScript.src = `//dapi.kakao.com/v2/maps/sdk.js?appkey=${process.env.NEXT_PUBLIC_KAKAO_JAVASCRIPT_KEY}&libraries=services,clusterer,drawing&autoload=false`;
document.head.appendChild(mapScript);
}
// 지도 그리기
const onLoadKakaoMap = () => {
window.kakao.maps.load(() => {
const options = {
center: new window.kakao.maps.LatLng(33.450701, 126.570667),
level: 2,
};
map = new window.kakao.maps.Map(mapRef.current, options);
});
};
onLoadKakaoMap();
mapScript.addEventListener('load', onLoadKakaoMap);
return () => {
mapScript.removeEventListener('load', onLoadKakaoMap);
};
}, []);
정말 기본적인 방법을 썼다.
바로 document가 생성되고 난 이후 script를 동적으로 생성해 넣어주는 것이다.
그리고 script의 load 이벤트를 잡아 이벤트 핸들러로 지도를 그리는 함수를 실행시켰다.
이렇게 하니 원하는대로 지도를 사용하는 페이지에서만 지도 관련 스크립트를 다운받아 사용할 수 있게 되었다.
하지만 map script가 로드될 때에만 지도를 그리고 있고 map이라는 아이디를 가진 element가 있다면 map script를 다시 생성하는 것이 아니기 때문에 이미 map script가 있는 경우에는 지도가 렌더링되지 않는 이슈가 있었다.
const mapScript = document && document.createElement('script');
useEffect(() => {
// kakao map script 세팅
if (!document.getElementById('map')) {
mapScript.id = 'map';
mapScript.async = true;
mapScript.src = `//dapi.kakao.com/v2/maps/sdk.js?appkey=${process.env.NEXT_PUBLIC_KAKAO_JAVASCRIPT_KEY}&libraries=services,clusterer,drawing&autoload=false`;
document.head.appendChild(mapScript);
}
// 지도 그리기
const onLoadKakaoMap = () => {
window.kakao?.maps.load(() => {
const options = {
center: new window.kakao.maps.LatLng(33.450701, 126.570667),
level: 2,
};
map = new window.kakao.maps.Map(mapRef.current, options);
});
};
mapScript.addEventListener('load', onLoadKakaoMap);
if (document.getElementById('map')) onLoadKakaoMap();
return () => {
mapScript.removeEventListener('load', onLoadKakaoMap);
};
}, []);
따라서 map이라는 아이디를 가진 element가 있을 때 지도를 그리는 함수를 호출함으로써 문제를 해결할 수 있었다.
엄청 고수같아요