본 게시물은 기존에 사용했던 Naver 지도 API에서 Kakao 지도 API로 전환하는 과정을 담았다.
사용 스택:Next.js
TypeScript
개인적인 이유로 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]);