React

[React] Kakao map api 1

JungCw 2024. 11. 8. 15:20

이번 프로젝트에서 가장 중요했던 것 중에 하나가 지도 객체를 사용하는 것이었다.

 

내 일정이나 장소 등을 보여주기 위해선 아무래도 지도 위에 표기해주는 것이 직관적이고 편리하다고 생각해서였다.

 

kakao, naver, google map등이 있었는데 아무래도 일단은 국내 데이터를 다룰 것이고, 처음 이용해보는 것이기에 kakao map api를 선택했다.

 

Kakao map api

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

 

웹에서의 설정 작업은 설명이 많이 되어있으니 스킵하겠다.

 

public/index.html 파일에

<script type="text/javascript" src="//dapi.kakao.com/v2/maps/sdk.js?appkey=여기에 발급받은 APP KEY를 넣으시면 됩니다."></script>

APP KEY값을 수정해서 삽입해준다. (header, body 두 곳 어디에 넣어도 괜찮다.)

 

api 연동은 되었으니 이제 내 코드에서 가져다 쓰면된다.

 

기본적인 지도 생성부터 해보자.

 

과정은 간단히 요약하면, 지도 설정(보여줄 위치 좌표 설정, 지도 확대 정도(레벨) 설정) -> 지도를 보여줄 DOM요소를 생성(<div> 등) -> 해당 DOM요소에 지도 생성 순으로 진행된다.

 

import React, { useEffect } from "react";

const { kakao } = window;  //'kakao' is not undefined 에러 해결

export const Map = () => {
  const container = document.getElementById('map'); // 지도 DOM 요소 설정(id)
  
  useEffect(() => {
    const position = new kakao.maps.LatLng(33.450701, 126.570667);
    const options = {
      center: position, // 지도의 중심 좌표
      level: 3, // 지도 확대 레벨
    };
    const map = new kakao.maps.Map(container, options);
  }, []);

  return (
    <div id="map" style={{ width: "500px", height: "500px" }}></div>
  );
};

 

이렇게 하면 일단 기본적인 지도가 표시된다.

 

다만, 이렇게 하면 React의 랜더링 주기 상 만약 지도를 띄워줄 DOM요소가 존재하지 않는 시점에 document.getElementById('map')로 접근하면 에러가 발생할 수 있다.

또한, 코드의 가독성과 유지보수를 위해 맵을 생성하는 이 코드를 따로 컴포넌트로 제공하게 되는데, 한 페이지에서 여러 맵을 띄우기 위해 컴포넌트를 여러번 재사용하게 되면 id값의 충돌이 발생하는 것 같았다.

 

이러한 문제점을 해결하기 위해 useRef를 사용하는게 좋다.

 

import React, { useEffect, useRef } from "react";

export const Map = () => {
  const container = useRef(null) // 지도 DOM 요소 설정
  
  useEffect(() => {
    const position = new kakao.maps.LatLng(33.450701, 126.570667);
    const options = {
      center: position, // 지도의 중심 좌표
      level: 3, // 지도 확대 레벨
    };
    const map = new kakao.maps.Map(container, options);
  }, []);

  return (
    <div style={{ width: "500px", height: "500px" }} ref={container}></div>
  );
};

 

이렇게 useRef를 사용해서 DOM요소를 지정해주면 위의 두가지 문제를 해결할 수 있다.

 

그런데 여기서 또 다른 에러도 발생했었다.

React의 Swiper 라이브러리 안에 지도를 삽입하니 슬라이드를 넘기면 지도가 아예 표현되지 않는 문제가 발생했다.

또한, 오버레이나 마커 등을 여러 개를 다루게 되면 상태변화에 의해서 지도가 여러번 랜더링 되고, 이로 인해 무한루프가 발생하는 경우도 존재했다.

 

랜더 문제와 무한루프를 해결하기 위해서 커스텀 훅으로 제작하기로 하였다.

 

import { useEffect, useState } from "react";

const { kakao } = window;

const useFetchMaps = () => {
	const locations = (지도 중심 값);  //props 등으로 제공받는 방식
    const [mapDetails, setMapDetails] = useState(null);

    useEffect(() => {
        if (locations.length > 0) {
            const options = {
                center: (지도 중심),
                level: 3
            };
            
            setMapDetails({
                option: options
            });
        }
    }, [locations]);

    return mapDetails;
};

export default useFetchMaps;

 

이런 형태로 제작해두면 추후에 마커나 오버레이를 추가하고 외부 라이브러리와 함께 사용할 때에도 에러를 해결하기 수월해진다.