
본 게시물은 기존에 사용했던 Naver 지도 API에서 Kakao 지도 API로 전환하는 과정을 담았다.
사용 스택:Next.jsTypeScript
개인적인 이유로 Naver 지도 API를 사용하였다가 Kakao 지도 API로 전환하게 되었다. 다행히 지도 API를 처음 생성하는 것보다는 덜 오래 걸렸지만 사용법이 완전히 똑같지 않기 때문에 부가로 더 이해해야 할 것이 많았다. 지도 생성하기 뿐만 아니라 지도를 클릭해서 주소를 가져오는 것, 네이버에는 없었던 키워드로 주소 검색하기도 차례차례 구현해보며 "Kakao Map 전환기" 시리즈를 만들어 볼 예정이다.
본 게시물에서는 script를 불러오고 지도를 생성하면서 어떤 에러를 마주했는지, Naver API와 다른점이 무엇인지를 정리해보았다.
Kakao Map API 사용하기부터 먼저 다뤄보겠다.
Naver 지도 API와는 다르게 공식적으로 TypeScript와 사용할 수 있는 패키지가 없다. 그렇기 때문에 TypeScript와 같이 사용하는 방법은 두가지가 있는데, 첫번째는 전역적으로 kakao를 선언하는 것이 있고, 두번째로는 오픈 소스로 기여된 Kakao API의 타입이 정의 되어있는 패키지를 설치하여 사용하는 것이다.
kakao에서 발생하는 타입에러를 막을 수 있다.// _app.tsx
declare global {
interface Window {
kakao: any;
}
const kakao: any;
}
// 설치
$ npm install kakao.maps.d.ts --save-dev
// tsconfig.json 패키지 추가
{
...,
"compilerOptions": {
...,
"types": [
...,
"kakao.maps.d.ts"
]
}
}
(패키지에 대한 더 자세한 내용은 JaeSeo Kim - kakao.maps.d.ts 참고)
<Script type="text/javascript" strategy="beforeInteractive" src="//dapi.kakao.com/v2/maps/sdk.js?appkey=발급받은 JavaScript 키&libraries=services&autoload=false"></Script>
beforeInteractive로 값을 넣어주는데 이는 어떠한 코드보다도 먼저 script를 먼저 로드하게 도와준다. (기본값은 afterInteractive로 script가 빠르게 로딩 되지만 다른 페이지에 있는 코드가 먼저 실행될 수 있다.)//로 시작하는데이 상대 프로토콜을 사용하면 사용자의 http, https 환경에 따라 자동으로 해당 프로토콜을 따라가게 된다고 설명되어있다. Kakao Maps API - 시작하기libraries=사용할라이브러리load 메서드를 사용하면 된다.Next.js를 사용하고 있다면, _document.tsx 파일로 들어가서 <Head>태그 안에 script를 넣어준다.
// _document.tsx
import { Html, Head, Main, NextScript } from 'next/document';
import Script from 'next/script';
export default function Document() {
return (
<Html lang="ko">
<Head>
<Script
type="text/javascript"
strategy="beforeInteractive"
src={`//dapi.kakao.com/v2/maps/sdk.js?appkey=${process.env.NEXT_PUBLIC_KAKAO_API_KEY}&libraries=services&autoload=false`}
></Script>
</Head>
<body>
<Main />
<NextScript />
</body>
</Html>
);
}
이전에 Naver 지도 API로 작업했던 것 그대로 가져와 주었다. (⚡️"Naver 지도 사용하기"를 정리한 블로그)
<div id='map' className='w-96 h-96'>
// 사용자의 위치를 가져오기 전까지는 로딩을 보여준다.
{typeof myLocation === 'string' && <Loader />}
</div>
useRef와 사용자의 현재 위치좌표를 가져와 줄 myLocation을 가져와 준다. 이 둘은 지도를 생성할 시점을 감시하기 위해 useEffect의 의존배열에 넣어준다. 사용자의 현재 위치를 가져오는 방법은 이 블로그를 참고하여 커스텀 훅으로 만들어주었다.// src/components/KakaoMap.tsx
import { useRef } from 'react'
import useGetCurrentLocation from '../../hooks/useGetCurrentLocation';
export const KakaoMap = () => {
const mapRef = useRef<HTMLElement | null>(null);
const myLocation = useGetCurrentLocation();
...
useEffect(() => {
// 지도 생성 함수
}, [mapRef, myLocation]);
};
kakao.maps.load(callback)export const KakaoMap = () => {
...
const initMap = () => {
// 사용자 위치를 받아왔다면 지도를 생성한다.
if (typeof myLocation !== 'string') {
// 지도를 표시할 요소 id
const mapContainer = document.getElementById('map'),
// 지도를 생성할 때의 옵션 (중심좌표, 확대레벨 등등)
mapOption = {
center: new kakao.maps.LatLng(myLocation.latitude, myLocation.longitude),
level: 3,
};
// kakao.maps.Map(container, options)를 사용하여 지도를 생성한다.
const map = new kakao.maps.Map(mapContainer as HTMLElement, mapOption);
(mapRef as MutableRefObject<any>).current = map;
}
};
useEffect(() => {
// 스크립트가 다 load된 후 initMap을 실행하여 지도를 생성해준다.
kakao.maps.load(() => initMap());
}, [mapRef, myLocation]);
};
Naver 지도 API와 다른 점이 크게 없어 전환 작업이 그렇게 어렵진 않았다.
NAVER 지도 API 타입 정의 파일이 있는 반면, 카카오는 아직 없는 것으로 보인다.
Naver script:
https://openapi.map.naver.com/openapi/v3/maps.js?ncpClientId=${process.env.MAP_KEY}&submodules=geocoder&callback=initMap
Kakao script
https://dapi.kakao.com/v2/maps/sdk.js?appkey=${process.env.KAKAO_API_KEY}&libraries=services&autoload=false
// naver
const map = new naver.maps.Map('map');
// kakao
const map = new kakao.maps.Map(document.getElementById('map'), options);

또한, kakao는 map을 꾸며주는 options가 없으면 에러가 발생한다.
성공적이라면 사용자의 현재 위치를 지도로 보여준다.


script태그가 다 로드 되기 전에 kakao API를 사용하는 코드가 먼저 실행 됐기 때문에 발생하는 에러이거나, 타입스크립트를 기반으로 하는 프로젝트라면 타입이 지정되지 않았기 때문이다.
해볼만한 시도 1:
script태그 src 제일 뒤에 autoload=false 추가하기.
해볼만한 시도 2:
script태그에 strategy 속성을 추가하여 beforeInteractive로 설정해준다.
해볼만한 시도 3:
전역에 kakao 선언하기
declare global {
interface Window {
kakao: any;
}
const kakao: any;
}

만약 useEffect의 의존배열이 빈 배열이라면 지도가 렌더링 되지 않으므로 사용자 위치를 가져왔을 때 생성된 지도를 가져올 수 있도록 참조한 지도 ref와 사용자 위치를 의존배열에 넣어준다.
useEffect(() => {
kakao.maps.load(() => initMap());
}, [mapRef, myLocation]);