
지도 API에는 다양한 종류가 있음
우리나라에서 가장 많이 사용하는 것은 구글, 네이버, 카카오에서 제공하는 지도 API
각 API 간에는 제공하는 기능의 종류, 비용 문제 등의 차이가 있기에,
차후 서비스 개발 시 이러한 차이점을 고려하여 어떤 API를 사용할 지 선택가능




<script type="text/javascript" src="//dapi.kakao.com/v2/maps/sdk.js?appkey='JavaScript 앱 키 입력'"></script>
appkey= 부분에 복사한 javascript 키를 넣어서 kakao의 map관련 제공 기능을 다운받음
이후 위 코드를 입력하여 화면상에 kakao map 을 표출
[BUT!]
Next.js 는 SSR(서버사이드 렌더링)을 지원하기 때문에 화면이 렌더링 되기전까지 해당 코드에서 사용중인 document 객체는 화면이 렌더링 되기 전까지는 undefined 상태이기에 오류가 발생!!
SSR(서버사이드 렌더링)으로 인한 이슈 해결
document(DOM) 이라는 것은 존재하지 않기 때문에 document is not defined 라는 에러가 발생함declare const window: typeof globalThis & {
// window라는 것의 타입은 globalThis(전역 설정 This) 이며, &(그리고) 그 타입에는 kakao 도 있다고 알려주는 것 (타입스크립트 에러 해결법)
kakao: any;
};
export default function kakaoMapPage(): JSX.Element {
useEffect(() => {
const container = document.getElementById("map"); // 지도를 담을 영역의 DOM 레퍼런스
const options = {
// 지도를 생성할 때 필요한 기본 옵션
center: new window.kakao.maps.LatLng(33.450701, 126.570667), // 지도의 중심좌표.
level: 3, // 지도의 레벨(확대, 축소 정도)
};
const map = new window.kakao.maps.Map(container, options); // 지도 생성 및 객체 리턴
console.log(map);
}, []);
+a) 그냥 kakao 만 작성할 경우 에러 발생!!
center: new kakao.maps.LatLng(33.450701, 126.570667)
이런 식으로 kakao에서 그대로 값을 뽑으려 하면 에러가 발생하며 kakao를 찾지 못함
[원인]
외부에서 API를 받으면 window 객체에 새롭게 저장되는데, 일반적으로 객체에서 값을 뽑아올 때 Obj.A.B~ 로 뽑아오는 것처럼 kakao 또한 전역 스코프인 window 객체에서 해당 값을 뽑아와야 하기 때문
declare const window: typeof globalThis & {
kakao: any;
};
이후 declare 를 이용해 window의 타입을 globalThis(전역 객체)로 지정해 주고 & 연산자를 이용해 {kakao : any} 라는 타입형식을 추가해 줌으로써 Typescript 에러를 해결
-kakao는 외부에서 받아오는 API로 따로 window 객체안에 저장이 되지만, 외부에서 받아왔기 때문에 Typescript는 해당 타입을 추론하지 못함
-따라서 globalThis 라는 Typescript에서 제공하는 타입을 window 객체의 타입으로 지정하고 그 안에 kakao의 타입을 명시해서 넣어 줌
+a) 왜 globalThis로 타입을 지정해주는가 ?
globalThis 로 타입을 지정해 주는 이유는 타입스크립트는 그 한계점으로 인해 외부에서 받아오는 API 가 어떤 환경에서 사용되는지 알 수 없기에, API의 전역 객체를 알지못함globalThis 는 모든 환경(브라우저,node.js)에서 동일한 타입으로 작동하기 때문에 어떤 환경에서 사용되던지 타입을 제대로 지정해 줄 수 있음
이후 플랫폼 페이지에서 웹사이트 도메인을 등록
[이 과정을 끝내고 나면 화면에 지도 출력이 가능해짐]
import { useRouter } from "next/router";
export default function KakaoMapRoutingPage() {
const router = useRouter();
const onClickMoveToMap = () => {
router.push("/29-03-kakao-map-routed");
};
return (
<div>
<button onClick={onClickMoveToMap}>맵으로 이동하기 !</button>
</div>
);
}

import { useRouter } from "next/router";
export default function KakaoMapRoutingPage() {
// const router = useRouter();
// const onClickMoveToMap = () => {
// router.push("/29-03-kakao-map-routed");
// };
return (
<div>
{/* <button onClick={onClickMoveToMap}>맵으로 이동하기 !</button> */}
<a href="/29-03-kakao-map-routed">맵으로 이동하기 !!</a>
</div>
);
}
router 를 이용하지 않고 <a> 태그를 이용해서 페이지를 이동하면 정상적으로 이동되며 설정한 코드에 맞게 kakao map을 로드함 위의 결과가 발생하는 이유는 router 는 SPA(Single Page Application) 으로 동작하고, <a> 태그는 MPA(Multi Page Application) 으로 동작하기 때문
*router는 SPA 방식으로 동작하여 기존에 프론트 서버에서 모든 데이터를 다 다운받아 두었다가 필요한 페이지에 맞게 렌더링하기 때문에, useEffect 안의 kakao는 프론트서버에 존재하지 않고, 브라우저에서 정의되는 것임으로 에러가 발생했던 것!!
MPA (Multi Page Application)
서로 다른 url을 가진 페이지들이 각각 독립적으로 존재
렌더링하기 전에 각 리소스 파일 다운로드가 완료될 때까지 기다림 (동기)
페이지가 이동될 때마다 프론트 서버에서 페이지를 그리고, 브라우저로 HTML/CSS/JS 파일을 보내주는 작업 진행
*이는 주소창에 주소를 직접 입력해서 접속하는 방식과 동일
페이지 이동 시마다 서버에서 데이터를 다운받아 오기 때문에 비효율적
SPA(Single Page Application)
이후 페이지를 이동할 때, 페이지의 일부 컴포넌트만 교체하고 페이지를 다시 렌더링 (필요한 리소스만 요청, 전체 리렌더링 X)
요청한 리소스 파일은 다운로드와 동시에 렌더링 (비동기)
*미리 모든 페이지를 다운받기 때문에 최초 로딩은 조금 느리지만, 이후 페이지 이동 시 기존에 다운받은 페이지를 렌더링하기 때문에 압도적으로 로드 속도가 빠름
<a> 태그를 사용해도 되지만, 이는 페이지 이동 시마다 새로 다운받아 오기 때문에 비효율적이며, Next.js를 사용하는 의미가 없어짐import { useRouter } from "next/router";
import Link from "next/link";
export default function KakaoMapRoutingPage() {
// const router = useRouter();
// const onClickMoveToMap = () => {
// router.push("/29-03-kakao-map-routed");
// };
return (
<div>
{/* <button onClick={onClickMoveToMap}>맵으로 이동하기 !</button> */}
<Link href="/29-03-kakao-map-routed">
맵으로 이동하기 !!
</Link>
</div>
);
}
Next에서 자체적으로 제공하는 <Link> 태그를 활용하면 문제를 해결하면서 효율적인 사용이 가능해짐
*Link는 페이지 전환 시, 이동 될 페이지의 js 파일을 미리 다운받기 때문에 kakao를 제대로 찾을 수 있음 (에러발생 X)
<Link> 를 사용할 시, Next에서 제공하는 것이기에 SPA 방식으로 동작함
<Link> 는 시멘틱 요소를 가진 html 태그로 렌더링 되기 때문에 웹표준, 검색엔진 최적화 차원에서도 이점이 있음
[Link는 클릭 시 무조건 이동되고, router는 이동 시 로직을 작성하고 제한을 걸 수 있기 때문에 상황에 맞게 각각 사용할 필요가 있음]
script 태그의 비동기 작동 이슈
useEffect(() => {
// 여기서 직접 다운로드 받고, 다 받을때까지 기다렸다가 그려주기!!
const script = document.createElement("script"); // html에 script라는 태그(Element)를 만든다.
script.src =
"//dapi.kakao.com/v2/maps/sdk.js?appkey='JavaScript API Key'&autoload=false";
document.head.appendChild(script);
script.onload = () => {
window.kakao.maps.load(function () {
const container = document.getElementById("map");
const options = {
center: new window.kakao.maps.LatLng(33.450701, 126.570667),
level: 3,
};
const map = new window.kakao.maps.Map(container, options);
}
}
}
.onload 와 kakao에서 제공하는 kakao.maps.load 를 이용해서 문제 해결 가능
script.onload 로 script가 모두 다운되기까지를 기다린 다음, onload 함수 안에서 다시 kakao map 코드를 로드
결과적으로 script가 모두 다운된 다음, kakao map이 로드되기 대문에 순서에 맞게 로직이 동작하여 지도가 정상적으로 보일 수 있게 됨