서론
이번에 진행하는 프로젝트에서 지도를 통해 정보를 제공하는 기능이 필요했다.
많은 지도 API 중에서 하나를 선택해야 했는데 카카오맵을 사용하기로 했다.
그 이유는 카카오맵 API의 개발자 커뮤니티가 잘 활성화되어있고 공식문서 구성이 깔끔했다. 또한 프로젝트에서 다루게 될 지도의 영역이 서울시였고 주변 건물들의 위치정보가 잘 드러나야 했기 때문에 이러한 점들을 고려하여 카카오맵을 최종적으로 선택하게 됐다.
이 글을 통해 카카오맵 API를 좀 더 React 환경과 어울리게 사용하고자 고민했던 과정을 공유해보고자 한다.
카카오맵 API 불러오기
https://apis.map.kakao.com/web/guide/
공식문서에 카카오맵을 불러오는 방식이 잘 정리되어있지만 그래도 ! 작성해보겠다.
API 키 발급받기
우선 카카오맵API를 사용하기 위해서는 API 키를 발급받아야 한다.
https://developers.kakao.com/console/app
위의 링크에서 애플리케이션을 추가하면 API 키를 발급받을 수 있다. 우리는 Javascript 앱 키를 사용하게 될 것이다.
// .env.local
NEXT_PUBLIC_KAKAO_API_KEY={API KEY가 들어가게 될 곳}
API 키를 노출하지 않기 위해 환경변수 파일을 생성해서 관리하기로 했다.
스크립트 추가하기
render() {
return (
<Html>
<Head>
<script
type="text/javascript"
src={`//dapi.kakao.com/v2/maps/sdk.js?appkey=${process.env.NEXT_PUBLIC_KAKAO_API_KEY}&libraries=services`}
/>
</Head>
<Main />
<NextScript />
</Html>
);
}
next.js를 사용하고 있는 프로젝트여서 _document.tsx 파일의 render() 메서드를 위와 같이 수정했다.
next.js를 사용하지 않는 환경이라면 리액트의 경우 index.html에 스크립트를 추가해주면 된다.
이 때 주의해야할 점은 자바스크립트 코드가 실행되기 전에 스크립트가 로드되어야한다.
이제 우리의 프로젝트에서 카카오 맵 API를 사용할 준비가 끝났다.
카카오맵을 조금 더 편리하게 사용할 수 있도록 커스텀 훅을 만들어보자.
왜 커스텀 훅인가?
사실 처음부터 커스텀 훅을 구현할 생각은 없었다.
우선 카카오맵API를 사용하기 위해서는 kakao 객체에 접근해야 하는데 이 kakao 객체는 브라우저 전역 객체인 window 안에 포함되어있다. 즉, 항상 다음과 같은 방식으로 사용해야 했다.
const { kakao } = window;
하지만 React 환경에서 위처럼 kakao 객체에 바로 접근할 수 없다.
화면이 렌더링 되기 전에는 브라우저의 전역 객체인 window를 인식하지 못하기 때문에 아마 window가 정의되지 않았다는 에러를 접하게 될 것이다.
때문에 화면이 렌더링 된 이후에 카카오맵과 관련된 로직에 접근해야 하는 제약이 발생한다. 이 제약은 코드 구조를 다음과 같이 강제하게 만들었다.
useEffect(() => {
const map = new window.kakao.maps.Map(containerRef.current, { center: defaultLocation });
// map을 사용하는 로직
// map을 사용하는 로직
// map을 사용하는 로직
// map을 사용하는 로직
}, [])
프로젝트에서 지도와 관련된 요구사항은 단순히 지도를 나타내는 것에서 끝나는 게 아니었다.
지도와 인터랙션을 하며 화면 상의 요소를 변경해야 했고 이 부분에서 코드 로직이 길어질 가능성이 높다고 생각했다.
또한 다양한 파일에서 이런 구조의 코드를 반복적으로 작성하게 되는 일이 빈번할 것이라고 생각했다.
이러한 부분들을 고려해보았을 때 지도를 생성하고 그 지도를 핸들링하는 함수를 반환하는 커스텀 훅을 만들면 코드의 중복을 제거할 수 있으며 사용성을 높일 수 있다고 판단했다.
지도 커스텀 훅 useMap 구현하기
카카오맵 메서드에 대한 설명은 기술하지 않겠다. 내가 작성하는 것보다 공식문서를 참조하는 것이 훨씬 나을 것 같다!
내가 초기에 생각했던 useMap의 구조와 목표는 다음과 같았다.
지도가 담기게 될 컨테이너의 ref만 useMap의 파라미터로 제공하면 해당 컨테이너 안에 지도가 렌더링 되는 커스텀 훅을 만들자.
지도를 담을 컨테이너의 ref를 useMap의 파라미터로 넘겨주기만 하면 첫 렌더링 이후에 해당 컨테이너 요소에 지도를 생성한다.
또한 카카오맵 인스턴스인 map을 export 함으로써 지도가 생성되는 과정에 대한 이해 없이도 카카오맵 인스턴스에 있는 여러 메소드들을 사용할 수 있게 된다.
주소로 카카오맵 좌표 객체 얻어내기
string 타입의 주소를 인자로 받아 해당 주소의 카카오맵 좌표 객체를 반환하는 함수이다.
Promise를 사용해서 await 할 수 있도록 구현했다.
주소 검색하고 해당 위치로 지도 중심 이동하기
주소에 커스텀 마커 찍기
위에서 구현한 주소 검색 함수를 사용해 지도 위에 커스텀 마커를 생성하고 해당 마커를 클릭했을 때 말풍선 같은 커스텀 오버레이가 나타나도록 이벤트를 부착해보자.
이 부분에서 중요한 포인트는 26번 라인이다.
customOverlay.setContent 함수는 커스텀 오버레이의 콘텐츠를 세팅해준다.
하지만 이 함수의 인자로는 ReactElement 와 ReactComponent를 넘겨줄 수 없다. 이 부분 때문에 커스텀 오버레이의 마크업 구조를 설계하고 스타일링하는 방식에 대해 고민이 많았다. 공식문서 상으로 확인해보았을 때 가능한 형식은 DOM Element 와 마크업 문자열 이 두 가지였다.
이 두 가지 중에 어떤 방식으로 진행할지 고민했었는데 마크업 문자열을 전달하는 것으로 결정했다.
DOM API를(document.createElement, document.appendChild 등) 사용해서 생성한 DOM Element를 전달하는 방법은 마크업의 구조를 한눈에 파악할 수 없다고 생각했다.
const template = `
<div class="my-template">
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
</ul>
</div>
`
위와 같은 방식으로 마크업을 문자열로 나타내면 한 눈에 이 요소가 어떤 구조를 갖고 있는지 파악할 수 있다.
스타일링은 템플릿에 클래스네임을 지정하고 styled-component의 css 모듈을 사용해서 해당 클래스네임에 스타일을 부여했다.
강력한 메서드를 장착한 useMap
위에서 구현한 메소드를 export 함으로써 우선 목표로 했던 기능을 갖춘 useMap 커스텀 훅을 완성했다.
마치며
사실 이 커스텀 훅의 완성도가 높지는 않다.
현재는 카카오맵 인스턴스를 state로 관리하지 않고 Redux를 도입해서 전역적으로 상태를 관리하고 있다.
또한 현재 지도에 생성되어있는 커스텀 마커의 리스트를 두어 어떤 정보를 담고 있는지, 현재 클릭되어 커스텀 오버레이가 보이는 상태인지 등을 알 수 있다.
다음에는 리덕스로 마이그레이션 하는 과정과 그 결과물에 대한 포스팅을 작성해보고 싶다!
'유연해지기 > etc.' 카테고리의 다른 글
Yarn Berry로 node_modules를 해치우자 (2) | 2022.06.13 |
---|---|
vscode에서 typescript warning, error 정보 안 보일 때 (0) | 2021.11.01 |
PostCSS에 대해 알아보자 (PostCSS란?) (0) | 2021.10.28 |