[ 공모전 ] 지도 페이지 : Next.js Page Router에서 KakaoMap 띄우기

최문길·2024년 6월 22일
0

공모전

목록 보기
15/46

카카오 맵

React에 카카오맵을 설정 하고 map을 불러오는데, 여러 방법들, 문제점등의 글이 작성되어있었다.

여러 블로그와 공식문서를 읽어보고 내가 "이해"한 것을 적어본다.

DOM 조작으로 명령형으로 카카오맵 띄우기

카카오맵 공식문서와 블로그에서 자주 볼 수 있는 것이 있다.

1. 카카오맵SDK Script를 첨부하기

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

먼저 script를 index.html에 첨부하여 windowkakao 객체를 넣어준다.
-> 실행코드보다 먼저 선언되어야 window객체 안에 kakao를 실행할 수 있으니까

2. Dom 조작하기

특정 컴포넌트 파일을 생성하고 document.getElementById('아이디이름') 으로 그 요소안에 kakaoMap을 주입해준다.

const { kakao } = window;

const KakaoMap = () => {

    useEffect(() => {
        const container = document.getElementById('map');
		const options = {
			center: new kakao.maps.LatLng(33.450701, 126.570667),
			level: 3
		};
        const map = new kakao.maps.Map(container, options);
    }, []);

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

map이라는 아이디를 먼저 선언 후, 그 이후에 사이드 이펙트인 useEffect로 카카오 맵을 첨부한다.

명령형 + 선언형 조합으로 조작 및 기능

조작하고, 기능 넣고 휘뚜루 마뚜루 하고 싶으면

const KakaoMap = () => {
  //...
  const mapRef = useRef<kakao | null>(null)
  const [state,setState] = useState(state) //예시일뿐입니다.
  //...
  useEffect(() => {
		//...생략
        const map = new kakao.maps.Map(container, options);
    	if(!mapRef.current) mapRef.current = map
    
    	return (()=>//... map객체 삭제
                           )
    }, []);
   useEffect(() => {
     	// 원하는 작업을 하면 됩니다. 
     
    }, [state]);
  
  //... 생략

useRef를 통해 직접적으로 조건문을 걸어 라이프 사이클을 활용하여 useEffect 안에서 map을 없애고, 다시 map을 생성하며 지도api를 사용할 수 있다. 그리고 clean up function을 통해 unmount 할 때 map을 삭제해주면 깔끔해집니다.

위에 것만 보아도 어떻게 해야할지 감이 잡히는 것 같습니다. 저번 부트캠프 때 kakaoMap관련 자료조사 및 현재까지 조사하고 이해한 걸로 치면 4주짜리 이해한 건데, 혹시 틀린 내용이 있으면, 비판해주세요 비난말고요~~

Dom 조작으로 카카오맵을 설치?, 조작하는 방법을 간략히 알아봤지만, 무언가 찜찜한 느낌이 듭니다..

어쩔수 없이 위와 같이 DOM조작을 해야하나?? 무언가 리액트 스럽지 못하다는 느낌이 강력히 들고, 마음적으로 불편함이 커집니다.

선언형으로 조작하기 1

이렇게 불편함이 있지만, react이므로 react kakaomap이라고 구글링해보면 react용 kakaoMap이 있다.
react-kakao-maps-sdk를 사용하여 선언적 프로그래밍으로만으로도 카카오맵을 사용 할 수 있다.

현재 내 프로젝트는 Next.js page router 를 사용하고 있다.

먼저 react-kakao-maps-sdk를 설치하자

pnpm i react-kakao-maps-sdk

그런다음에 KakaoMap.tsx 파일을 생성 후 다음과 같이 작성해보자

import Script from 'next/script';
import { Map } from 'react-kakao-maps-sdk';

const KAKAO_SDK_URL = `//dapi.kakao.com/v2/maps/sdk.js?appkey=${NEXT_PUBLIC_KAKAO_APP_JS_KEY}&autoload=false`;

const KakaoMap = () => {
  return (
    <>
      <Script src={KAKAO_SDK_URL} strategy="beforeInteractive" />
      <Map center={{ lat: 33.450701, lng: 126.570667 }} style={{ width: '100%', height: '100%' }}>
      </Map>
    </>
  );
};

export default KakaoMap;

여기서 중요 포인트는 다음 2가지

  • KAKAO_SDK_URL에 반드시 autoload=false 를 추가해야 합니다. 만약 이 파라미터를 생략하거나 true 값을 주게 되면, kakao.maps 제대로 로딩하지 못하게 되어
    TypeError: kakao.maps.LatLng is not a constructor 오류가 발생합니다.
  • Script 컴포넌트의 strategy prop의 값을 beforeInteractive로 지정해주어야 합니다.
    default는 afterInteractive로 되어있는데, nextjs모듈들이 형성되기전부터 kakaoMap을 로드하기 위해서 beforeInteractive로 지정했습니다.

next.js PageRouter/Script 전략

이렇게 하면 react-sdk에서 제공하는 Map Component와 Marker, Circle 등 다양한 리액트 Component를 활용해서 프로젝트에서 사용 하면 된다.

위의 Script를 사용하여 카카오맵을 조작했지만, 조금더 좋은것이 없을까 생각하게 되었다. ( 이놈의 욕심과, 집작은.... 진짜 )

선언형으로 조작하기 2

react-kakao-maps-sdk에서 내장되어있는 class인 useKakaoLoader를 사용해서 카카오 맵을 주입할 수 있다.

해당 hook은 cleanup 시점에도 Kakao Map Api를 제거 하지 않고, 동일한 hook를 여러 위치에서 호출 하더라도 최초 한번만 Loading 됩니다.
내부에서 반환하는 loading state는 hook를 통해 제어할 때 사용하도록 제공하는 state 입니다.
loading를 통한 Map 컴포넌트를 conditional rendering를 하지 않아도 됩니다.
ReactKakaoMapSDK useKakaoLoader

kakao Map API를 최초 한번만 불르고 unmount 되었다가 다시 mount될 때도 살아있다라고 이해 했다. Next.js page router에서는 page 단으로 최적화를 진행하므로 무리가 없다 판단하였고, Map Page에서는 depths가 0이므로, 사용하기에 적합하다고 판단 했다.

useKakaoLoader Hook을 만들어보자

useKakaoLoader는 말그대로 훅이기에 Hook으로 뺀 후에 loading과 error를 뱉어 내어 UI 최적화에도 사용하기로 생각하였다.

// src/hooks/client/map/kakao-map
import { useKakaoLoader as useKakaoLoaderOrigin } from 'react-kakao-maps-sdk';
const useKakaoLoader = () => {
  const [loading, error] = useKakaoLoaderOrigin({
    appkey: process.env.NEXT_PUBLIC_KAKAO_MAP_API_KEY as string,
    libraries: ['clusterer', 'drawing', 'services'], // 사용하고싶은 다른 라이브러리 추가 
  });

  return [loading, error];
};

export default useKakaoLoader;

쌈뽕하다.
loading, error 관련 UI 처리도 할 수 있고..... React에서 "cluster" , "drawing" 등 다른 카카오맵 라이브러리를 사용하고 싶으면 script에 넣어줘야하는데, 객체안에 라이브러리들을 명시 해주니 한눈에 보기에도 좋다.

선언형으로 맵 불러오기

이제 훅을 호출하자

import useKakaoLoader from '@/hooks/client/map/kakao-map/useKakaoLoader';
import { Map } from 'react-kakao-maps-sdk';

const KakaoMap = () => {
   const [loading, error] = useKakaoLoader();

  if (loading || error) return <Skeleton type="map" />;
  return (
      <Map center={...} style={...}>
      </Map>
  );
};

export default KakaoMap;

코드가 이쁘고, 쌈뽕하지 않은가.
결국은 위의 코드를 위해 이틀을 고생한 것이 후회가 안남았다.


위의 코드를 작성하기 위해 여러 부분을 알아보면서
Nextjs에서 Script를 알게 되었고, Script의 옵션관련하여서 알게 되었다는 점도 좋았고,
제일 중요한 부분은
외부 API를 사용하는데 자신감이 생겨져서 좋았다.

참고
Nextjs kakao 블로그
React스럽게 kakaoMap
ReactKakaoDocs
블로그1/React
블로그2/React

0개의 댓글

관련 채용 정보