멋쟁이 사자처럼에서 진행하는 중앙 해커톤을 준비하면서 카카오맵 API를 통해 지도를 화면에 그리는 기능을 구현하게 되었습니다. 카카오에서 제공한 공식문서가 워낙 깔끔하게 잘 정리되어있어 빠르게 지도를 화면에 구현할 수 있었지만, 도중 몇몇 문제를 마주하여 고민했던 부분 역시 있었는데, 이 포스트에선 이러한 문제를 어떻게 해결했는지를 정리하여 비슷한 어려움을 겪고 있는 다른 개발자 분들에게 도움을 드리고자 합니다. (참고로 저는 Web API를 사용하여 구현했습니다.)
로컬 환경에서 테스트할 수 있도록 사이트 도매인 등록하기
로컬 환경에서 카카오맵 API가 올바르게 동작하는 지 확인하기 위해선 로컬 주소를 사이트 도매인으로 등록해주면 됩니다. 저는 처음에 공식문서에서 '웹 서버를 실행시키라'는 언급이 있어 웹 서버가 반드시 있어야 하는 것인가 생각했었는데, 서버 필요 없이 로컬 환경에서도 충분히 테스트가 가능했습니다. (React의 기본 로컬 주소 포트는 3000이라 저는 사이트 도메인을 아래 사진과 같이 등록했습니다.)
TypeError: kakao.maps.LatLng is not a constructor 오류 해결하기
공식문서를 바탕으로 코드를 작성하던 중 위와 같은 에러를 마주하게 되었는데, 검색을 해보니 해당 문제에 대한 해결법은 2가지가 있었습니다.
우선 해당 에러가 발생하는 이유는 LatLng 메서드가 아직 로딩 중이라 생성이 되지 않은 상태에서 이를 생성자 함수 호출하려 했기 때문입니다. 따라서, 스크립트의 로딩이 끝난 후 콜백을 통해 객체에 접근할 수 있도록 하기 위해 공식문서에선 다음과 같은 방법을 안내해주고 있습니다. https://apis.map.kakao.com/web/documentation/#load_load
v3 스크립트를 동적으로 로드하기위해 사용한다.
스크립트의 로딩이 끝나기 전에 v3의 객체에 접근하려고 하면 에러가 발생하기 때문에
로딩이 끝나는 시점에 콜백을 통해 객체에 접근할 수 있도록 해 준다.
비동기 통신으로 페이지에 v3를 동적으로 삽입할 경우에 주로 사용된다.
v3 로딩 스크립트 주소에 파라메터로 autoload=false 를 지정해 주어야 한다.
제 완성된 React 코드는 다음과 같습니다.
import Head from "next/head";
import { useEffect } from "react";
export default function Map({ latitude, longitude }) {
const apiKey = "제 JavaScript 앱 키 입니다.";
// 카카오 API 호출
useEffect(() => {
const script = document.createElement("script");
script.async = true;
script.src = `//dapi.kakao.com/v2/maps/sdk.js?appkey=${apiKey}&autoload=false`;
document.head.appendChild(script);
script.addEventListener("load", () => {
window.kakao.maps.load(() => {
const container = document.getElementById("map");
const options = {
center: new window.kakao.maps.LatLng(latitude, longitude), // 초기 중심 좌표 (위도, 경도)
level: 3, // 지도 확대 레벨
};
new window.kakao.maps.Map(container, options);
});
});
}, []);
return (
<>
<div id="map" style={{ width: "100%", height: "400px" }}></div>
</>
);
}
< 위 코드 동작과정 설명 >
1. useEffect 훅: 이 코드는 컴포넌트가 마운트될 때 한 번 실행되며, 함수 내부의 코드 블록을 실행합니다.
2. 스크립트 엘리먼트 생성:
- document.createElement("script")를 사용하여 스크립트 엘리먼트를 생성합니다.
- script.async = true;는 스크립트를 비동기적으로 로드하도록 설정합니다.
- script.src는 로드할 스크립트 파일의 URL을 설정합니다. 여기서는 카카오 맵 SDK를 로드하는 URL을 생성합니다. autoload=false 파라미터는 SDK가 자동으로 로드되지 않도록 설정합니다.
3. 스크립트 로드:
- document.head.appendChild(script);를 사용하여 스크립트 엘리먼트를 <head> 요소에 추가합니다. 이로써 스크립트가 로드되기 시작합니다.
4. 스크립트 로드 완료 이벤트:
- script.addEventListener("load", () => { ... });는 스크립트 로드가 완료되었을 때 실행될 이벤트 리스너를 등록합니다.
- 이 이벤트 리스너 내부에서는 window.kakao.maps.load(() => { ... });를 사용하여 카카오 맵 SDK의 로드가 완료될 때까지 기다립니다.
5. window.kakao.maps.load 콜백:
- 카카오 맵 SDK가 로드되었을 때 실행되는 콜백 함수입니다.
- 콜백 함수 내부에서는 초기화 작업을 수행합니다.
- const container = document.getElementById("map");를 사용하여 지도를 표시할 DOM 요소를 가져옵니다.
- new window.kakao.maps.Map(container, options);를 사용하여 초기화된 지도 인스턴스를 생성하고 해당 DOM 요소에 표시합니다.
요약하면, 이 코드는 컴포넌트가 마운트되면 카카오 맵 SDK를 비동기적으로 로드하고, SDK 로드가 완료된 후에 지도를 초기화하여 지도를 화면에 표시하는 작업을 수행합니다.
이와 더불어, 작업 도중 인증 정보에 문제가 있을 때 발생하는 401 에러도 한 번 접했었는데, 저 같은 경우
script.src = `//dapi.kakao.com/v2/maps/sdk.js?appkey=${apiKey}&autoload=false`;
이 코드에서 '${apiKey}' 이렇게 apiKey 데이터를 작은 따옴표로 잘못 감쌌습니다. 혹시 해당 에러를 마주하신 분들 중 apiKey엔 도저히 이상이 없는 것 같다고 생각하고 계시다면 이 부분도 한 번 점검해보시기 바랍니다.
'◼ FrontEnd > ReactJS' 카테고리의 다른 글
[ReactJS] 관심사의 분리와 Custom Hook (0) | 2023.02.21 |
---|---|
[ReactJS] Dynamic Routing & Query String (0) | 2023.01.24 |
[ReactJS] Component의 분리와 재사용 (관심사의 분리) (0) | 2023.01.24 |
[ReactJS] 상수 데이터 & Mock Data + fetch 매소드 (0) | 2023.01.24 |
[ReactJS] Side Effect와 useEffect (0) | 2023.01.24 |