개발브롞으

[Next.js] 카카오맵 SDK 연결 - 카카오맵 동작원리와 구현 방법 (kakao api, kakao developers JS SDK) 본문

WEB/Next.js

[Next.js] 카카오맵 SDK 연결 - 카카오맵 동작원리와 구현 방법 (kakao api, kakao developers JS SDK)

총명한 주인장 2026. 2. 10. 22:18
728x90
728x90

이번 글은 카카오맵 SDK를 연결하는 과정을 담은 설명글이다.

완성된 코드는 글 맨 아래에 작성되어져있다.


 

 

 

⬇️ 카카오 지도 띄우는 법 공식 가이드 ⬇️

https://apis.map.kakao.com/web/guide/#step1

 


https://developers.kakao.com/

 

Kakao Developers

카카오 API를 활용하여 다양한 어플리케이션을 개발해 보세요. 카카오 로그인, 메시지 보내기, 친구 API, 인공지능 API 등을 제공합니다.

developers.kakao.com

 

 

지도 띄우기는 지도의 좌표를 넣어서 그 좌표 기준으로 지도를 생성하고 마커를 찍는 개념이다.

 

나는 현재 api에서 불러온 address 값이 '서울특별시 성동구 연무장길 xxx' 이런 형태이기 때문에 이 문자열 형태의 주소값을 좌표로 변환하는 과정을 거쳐서 지도에 좌표를 넣어줘야한다.

=> 이걸 해주는게 'Geocoder'임

 

[ 코드의 작업 과정 ]
1. 문자열의 주소값을 받아옴
2. Geocoder로 문자열을 위도(lat)과 경도(Ing)로 변환
3. 2에서 해준걸 지도 코드에 중심좌표로 넣어줘서 지도를 불러와줌
4. 2에서 불러온 좌표값을 마커 위치에도 활용

 


 

[ kakao developers 세팅하기 ]

✅ [ + 앱 생성 ]을 통해 현재 지도를 추가할 웹사이트를 등록해준다.

앱 생성

 

✅ 카카오맵 사용 설정의 상태를 ON으로 변경해준다.

 

 

 

✅ 여기에 내가 테스트할 로컬 주소와 배포된 주소를 추가해준다.

(추가하지 않으면 보이지 않는다.)

 

✅ 그리고 [플랫폼 키]에서 [JavaScript 키]를 복사해준다.

(아래 이미지에서 모자이크된 부분이 키가 있는 위치이다.)

 

 

✅ 그리고 아래 script에서 '여기에JS키붙여넣기' 부분에 복사해온 JavaScript 키를 넣어준다.

script 태그는 반드시 실행코드보다 먼저 선언되어야한다.

(위치는 html 파일 내 <head>, <body> 등 어떠한 위치에 넣어도 상관 없음)

import Script from "next/script";

<Script
  src={`//dapi.kakao.com/v2/maps/sdk.js?appkey=여기에JS키붙여넣기&autoload=false&libraries=services`}
  strategy="beforeInteractive"
/>

이 스크립트가 로드되면 브라우저 안에 자동으로 window.kakao가 생성됨

=> 브라우저(window) -[내부]→ kakao (카카오 SDK 전체)

(이 <script> 삽입을 통해 import 없이 아래에서 window.kakao로 사용할 수 있게됨)

 


 

[ 공식 문서 안내 ]

아래 이미지처럼 지도 띄우기 상황 별 예시 코드와 추가 기능에 대한 코드를 아래 링크에서 제공한다.

나는 마커(핀)가 있는 지도를 구현해야하기 때문에 '마커 생성하기'를 참고해 만들었다.

다양한 소스 코드를 제공하니 개발해야하는 지도에 맞춰 참고하여 제작하면 될 것 같다.

⬇️ 지도 코드 예시 공식문서 바로가기 ⬇️

 


 

[ 지도 구현하기 ]

나는 KakaoMap이라는 컴포넌트에서 props로 '서울특별시 성동구 연무장길 xxx' 같은 문자열형의 데이터를 받아오고 있었다.

따라서 이 문자열형 주소값을 좌표(위도, 경도)로 변환해주는 작업을 해줬다.

아래 코드에서 Geocoder()는 주소↔좌표 의 변환을 담당하는 객체이다.

✅ 코드 1 - 문자열 주소에서 좌표값 뽑아낼 준비

const geocoder = new kakao.maps.services.Geocoder();

 

 

나는 주소를 좌표로 변경해야하기 때문에 주소 문자열을 위도, 경도 좌표로 변경해주는 geocoder.addressSearch() 함수를 사용했다.

함수의 파라미터로 좌표로 변경할 주소를 넣어주고 콜백함수가 들어간다.

콜백함수는 찾은 좌표의 정보를 담은 result와 성공했는지 여부를 담은 status로 구성되어져있다.

geocoder.addressSearch(주소, (result, status)=>{})

 

 

result의 구조는 아래 예시와 같다.

// result 구조 예시
[
  {
    x: "127.043...",
    y: "37.544...",
  }
]

 

 

따라서 위도(lat)에 result의 인덱스 0번의 y 객체 값을 담고 경도(lng)에 result의 인덱스의 0번의 x 객체 값을 담도록 해준다.

그리고 status는 kakao.maps.services.Status.OK와 값이 같으면 주소 찾기에 성공한거고 아래 코드를 실행하고 주소를 못찾은 상태면 status와 kakao.maps.services.Status.OK의 값이 다르게 되기 때문에 이때는 리턴해준다.

 

 

LatLng()은 지도가 이해할 수 있는 형태로 위도와 경도를 묶어 만든 좌표 객체이다.

이걸 생성해주면 밑에서 굳이 위도, 경도를 계속 써줄 필요가 없다.

✅ 코드 2 - 문자열 주소에서 좌표값 뽑아내기

geocoder.addressSearch(address, (result: any, status: any) => {
        if (status !== kakao.maps.services.Status.OK) return;

        const lat = result[0].y;
        const lng = result[0].x;

        const coords = new kakao.maps.LatLng(lat, lng);
      });

 

 

 

Map()의 내부 구조를 살펴보면 컨테이너와 옵션으로 구성되어져있다.

Map()의 특징은 생성하는 순간 바로 렌더링되기 때문에 따로 리턴할 필요가 없다.

new kakao.maps.Map(컨테이너, 옵션)
  • 컨테이너 : 지도를 그릴 공간 (어디에 그릴지)
  • 옵션 : 지도를 그리는 방식 (어떻게 그릴지)

 

Map의 옵션 종류 의미 (기능)
center 지도 중심 좌표
level 확대/축소 정도
mapTypeId 일반지도/위성지도
draggable 드래그 가능 여부
scrollwheel 휠 확대 가능 여부

 

 

 

나는 useRef로 정해둔 div에 지도를 그릴 예정이기 때문에 아래 코드와 같이 작성해줬다.

✅ 코드 3 - 지도 그려주기

step 1) useRef로 어느 영역에 지도를 그릴지 설정한다.

const mapRef = useRef<HTMLDivElement>(null);

// return 영역
return <div ref={mapRef} style={{ width: "100%", height: "100%" }} />;

 

step 2) Map() 내부에 지도를 그릴 위치를 step 1에서 설정한 mapRef.current로 설정해준다.

             지도 옵션 값은 위에서 생성한 coords를 사용해 중심을 설정해줬다.

             map에 따로 담아준 이유는 마커를 띄울 때 사용되기 때문에 굳이 담아줬다.

const map = new kakao.maps.Map(mapRef.current, {
          center: coords,
          level: 3,
        });

 

 

이때 div는 도화지, Map은 그림판 프로그램, coords는 어디를 중심으로 그릴지, level은 확대 크기라고 생각하면 된다.

 

 

✅ 코드 4 - 마커 그려주기

마커는 position 속성에 지도에서 중심을 그린 것처럼 마커를 찍을 위치를 좌표로 넣어주면 된다.

그래서 position에 위도와 경도를 담은 coords를 넣어줬다.

여기까지의 과정이 마커를 생성한 과정이라면 마커를 띄워주기 위해서는 setMap()이 필요하다.

setMap()을 통해 map이라는 지도에 생성한 marker라는 마커를 붙이라는 의미가 된다.

const marker = new kakao.maps.Marker({
          position: coords,
        });
        marker.setMap(map);

 

[ 🚨 지도 작업하며 발생한 에러 ]

Cannot read properties of undefined (reading 'Geocoder')라는 에러가 발생했다.

=> kakao.maps.services가 준비 되지 않았는데 거기에서 Geocoder를 꺼내려해서 오류가 발생함💥

(window.kakao는 있는데 kakao.maps.services가 로드가 안된 상황)

 

 

[ 구조 ]

  • window.kakao → 카카오 SDK 전체
  • kakao.maps → 지도 기능 묶음
  • kakao.maps.services → 주소검색 기능 묶음
  • Geocoder → 주소를 좌표로 바꾸는 기능

⬇️ 구조 자세히 보기 ⬇️

더보기

window
 └ kakao
     └ maps
         ├ Map        → 지도 생성
         ├ Marker     → 마커
         ├ LatLng     → 좌표
         └ services
             └ Geocoder → 주소 → 좌표 변환

 

SDK 로딩 타이밍 문제

 

해결방법에 대해 결론부터 말하자면 layout.tsx에 넣은 <Script>의 autoload가 false여서가 문제였다.

autoload=false를 써두면 SDK가 자동으로 준비가 안되는 특징이 있다. (빠르게 생성되는 window.kakao 객체만 생긴 상태)

kakao.maps.load(() => {
  // 여기 안에서만 maps, services 사용 가능
});

그래서 위의 코드처럼 load로 감싸줘야 kakao.maps가 준비되고 services도 준비되고 그 다음에 코드를 실행할 수 있게 해준다.

 


 

 

[ 완성된 코드 ]

"use client";

import { useEffect, useRef } from "react";

interface KakaoMapProps {
  address?: string;
}
const KakaoMap = ({ address }: KakaoMapProps) => {
  const mapRef = useRef<HTMLDivElement>(null);

  useEffect(() => {
    /* eslint-disable @typescript-eslint/no-explicit-any */
    const kakao = (window as any).kakao;
    if (!kakao || !mapRef.current || !address) return;

    kakao.maps.load(() => {
      const geocoder = new kakao.maps.services.Geocoder();

      geocoder.addressSearch(address, (result: any, status: any) => {
        if (status !== kakao.maps.services.Status.OK) return;

        const lat = result[0].y;
        const lng = result[0].x;

        const coords = new kakao.maps.LatLng(lat, lng);

        const map = new kakao.maps.Map(mapRef.current, {
          center: coords,
          level: 3,
        });

        const marker = new kakao.maps.Marker({
          position: coords,
        });
        marker.setMap(map);
      });
    });
  }, [address]);

  return <div ref={mapRef} style={{ width: "100%", height: "100%" }} />;
};

export default KakaoMap;

 

 


728x90
728x90
Comments