카카오지도 API 응용하기

Kakao 지도 API

Kakao Developers

사이트에 들어가서 앱 키를 발급받아야 API를 사용할 수 있다.


순수 JS 라이브러리를 React에 적용하기

$ yarn create react-app cacaomap --template typescript
$ yarn start

<실제 지도를 그리는 Javascript API 불러오기>

index.html에 있는 head 와 body 가 모두 로딩된 다음,
body의 <div id="root"></div> 안에 작성한 리액트 프로젝트가 들어가게 된다.
index.html에다가 script 태그를 넣으면 리액트 프로젝트가 로딩되기 전에 카카오지도가 install 된다.

-script에 발급받은 key를 넣어도 인증이 되지 않았다고 오류창이 뜨는 경우 :
브라우저에서 개발자 도구를 이용해 누구나 HTML 코드를 볼 수 있어 다른 사람의 key를 탈취해
자신의 앱에 넣을 수 있음으로 카카오맵 이용권한을 뺏는 것을 방지하기 위해 자신이 등록한 사이트에서만
카카오맵키를 사용하는 것을 허용하고 있다.
-플랫폼 설정하기에서 자신의 사이트를 등록해주면 된다. [ex) http://localhost:3000]

<!-- public/index.html -->

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

브라우저에 지도띄우는 코드 작성

외부에서 CDN방식으로 <script> 태그로 가져오는 라이브러리들은 window.을 통해 접근 가능하고
타입스크립트의 경우 window에다가 declare를 통해서 interface안에 새로운 프로퍼티를 정의하여
함수들을 가져올 수 있다.

//src/App.tsx

import React, { useEffect } from "react";
import logo from "./logo.svg";

//타입스크립트에서 윈도우객체에 kakao 추가하는 방법
declare global {
    interface Window {
        kakao: any;
    }
}

function App() {
    //useEffect를 통해서 마크업들이 로딩된 이후에 실행될 수 있도록 코드 작성
    useEffect(() => {
        const container = document.getElementById("map");
        var options = {
            center: new window.kakao.maps.LatLng(33.450701, 126.570667),
            level: 3,
        };

        var map = new window.kakao.maps.Map(container, options);
    }, []);
    return (
        <div>
            <div
                id="map"
                style={{
                    width: 300,
                    height: 300,
                }}
            ></div>
        </div>
    );
}

export default App;

외부에서 정의된 함수를 가져올 때 코드 작성
-html script 함수를 먼저 작성, App.tsx 파일에서 불러온다.

<!-- public/index.html -->

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

<script>
    function loadMap() {
        const container = document.getElementById("map");

        var options = {
            center: new window.kakao.maps.LatLng(33.450701, 126.570667),
            level: 3,
        };

        var map = new window.kakao.maps.Map(container, options);
    }
</script>
// src/App.tsx

import React, { useEffect } from "react";
import logo from "./logo.svg";

declare global {
    interface Window {
        loadMap: () => void;
    }
}

function App() {
    useEffect(() => {
        window.loadMap();
    }, []);
    return (
        <div>
            <div
                id="map"
                style={{
                    width: 300,
                    height: 300,
                }}
            ></div>
        </div>
    );
}

export default App;

함수들이 어떤 타입의 매개변수를 원하는지 미리 파악하여 응용하기

*react에서는 id 쓰는 것을 권장하지 않는다
-> getElementById 대신 useRef를 통해 엘레먼트 가져오기

// src/App.tsx

import React, { useEffect, useRef } from "react";
import logo from "./logo.svg";

declare global {
    interface Window {
        kakao: any;
    }
}

function App() {
    const mapRef = useRef<HTMLDivElement>(null);

    useEffect(() => {
        if (mapRef.current) {
            var options = {
                center: new window.kakao.maps.LatLng(33.450701, 126.570667),
                level: 3,
            };
            var map = new window.kakao.maps.Map(mapRef.current, options);
        }
    }, []);
    return (
        <div>
            <div
                ref={mapRef}
                style={{
                    width: 300,
                    height: 300,
                }}
            ></div>
        </div>
    );
}

export default App;

리액트스럽게 코드 변경하기

-index.html에 script를 넣게되면 지도를 사용하지 않을 때에도 지도 자바스크립트를 로딩해야되는
이슈가 있고, index.html에 있는 외부 함수를 window를 통해 접근하는 것이 오류의 원인이기도 한다
[디버깅 할 때 검증하기 어려움] -> 성능 저하, 앱크기 증가 등 악영향이 있을 수 있다.
-동적으로 로딩하게 되면 필요할 때 지도가 보이는 페이지에서만 로딩할 수 있다.
-반드시 script가 로딩 된 이후에 카카오지도가 로딩되는 코드가 실행되어야 한다.

// src/App.tsx

declare global {
    interface Window {
        kakao: any;
    }
}

function App() {
    const mapRef = useRef<HTMLDivElement>(null);

    useEffect(() => {
        const script = document.createElement("script");
        script.src = document.head.appendChild(script);
        script.onload = () => {
            window.kakao.maps.load(() => {
                if (mapRef.current) {
                    var options = {
                        center: new window.kakao.maps.LatLng(
                            33.450701,
                            126.570667
                        ),
                        level: 3,
                    };
                    var map = new window.kakao.maps.Map(
                        mapRef.current,
                        options
                    );
                }
            });
        };
        return () => script.remove();
    }, []);

    return (
        <div>
            <div
                ref={mapRef}
                style={{
                    width: 300,
                    height: 300,
                }}
            ></div>
        </div>
    );
}

export default App;

카카오지도 응용하기

useRef를 이용하여 지역 이동 버튼 구현하기
-값이 새로 설정된다고 해도 리렌더링이 일어나지 않고 UI에 영향을 주지 않게 구현

// src/App.tsx

.
.
function App() {
    const mapRef = useRef<HTMLDivElement>(null);
    //useRef는 리액트가 리렌더링 되더라도 데이터를 계속 보관하고 있다.
    const map = useRef<any>(null);

    useEffect(() => {
        const script = document.createElement("script");

        script.src =
            "//dapi.kakao.com/v2/maps/sdk.js?appkey=발급받은 APP KEY를 넣으시면 됩니다&autoload=false";

        document.head.appendChild(script);

        script.onload = () => {
            window.kakao.maps.load(() => {
                if (mapRef.current) {
                    var options = {
                        center: new window.kakao.maps.LatLng(
                            33.450701,
                            126.570667
                        ),
                        level: 10,
                        draggable: false,
                    };
                    //current안에 있는 값은 리렌더링이 되어도 초기화되지 않는다.
                    map.current = new window.kakao.maps.Map(mapRef.current, options)
                }
            });
        };

        return () => script.remove();
    }, []);

    return (
        <div>
            {/* 지역이동하는 버튼만들기 */}
            <button
                onClick={() => {
                    map.current.setCenter(
                        new window.kakao.maps.LatLng(37.5665, 126.9780)
                    );
                }}
            >
                서울
            </button>
            <button
                onClick={() => {
                    map.current.setCenter(
                        new window.kakao.maps.LatLng(35.1796, 129.0756)
                    );
                }}
            >
                부산
            </button>
            <div
                ref={mapRef}
                style={{
                    width: 300,
                    height: 300,
                }}
            ></div>
        </div>
    );
}

export default App;

다른 속성 이용하기

-지도에 마커 추가하기
-마커 추가할 때 타이틀 입력 기능 추가
-여러번 추가 했을 때 리스트 생성
-마커 삭제 기능 추가

// src/App.tsx

function App() {
    const mapRef = useRef<HTMLDivElement>(null);
    //마커들의 정보를 저장해서 아래에 띄워주기
    const [markerList, setMarkerList] = useState<any[]>([]);
    const map = useRef<any>(null);

    useEffect(() => {
        const script = document.createElement("script");

        script.src =
            "//dapi.kakao.com/v2/maps/sdk.js?appkey=발급받은 APP KEY를 넣으시면 됩니다&autoload=false";

        document.head.appendChild(script);

        script.onload = () => {
            window.kakao.maps.load(() => {
                if (mapRef.current) {
                    var options = {
                        center: new window.kakao.maps.LatLng(
                            33.450701,
                            126.570667
                        ),
                        level: 10,
                    };
                    map.current = new window.kakao.maps.Map(
                        mapRef.current,
                        options
                    );
                    //마우스 오른쪽 버튼을 클릭하면 지도에 마크 생기게 하는 로직
                    window.kakao.maps.event.addListener(
                        map.current,
                        "rightclick",
                        (mouseEvent: any) => {
                            const latlng = mouseEvent.latLng;
                            //우클릭을 했을 때 타이틀 작성해주기
                            const title =
                                prompt("마커의 타이틀을 입력해주세요.");

                            //마커 생성하기
                            var marker = new window.kakao.maps.Marker({
                                map: map.current,
                                position: latlng,
                                title,
                            });
                            //마커가 추가될때마다 setMarkerList에 추가
                            setMarkerList((prev) => [...prev, marker]);
                        }
                    );
                }
            });
        };

        return () => script.remove();
    }, []);

    return (
        <div>
            <button
                onClick={() => {
                    map.current.setMapTypeId(
                        window.kakao.maps.MapTypeId.HYBRID
                    );
                }}
            >
                지도 타입 변경
            </button>

            <div
                ref={mapRef}
                style={{
                    width: 300,
                    height: 300,
                }}
            ></div>
            {
                // 만들어진 div가 click되었을 때 마커 제거
                markerList.map((value) => (
                    <div
                        onClick={() => {
                            value.setMap(null);
                            //state에서도 마커 제거
                            setMarkerList(
                                markerList.filter((v) => v !== value)
                            );
                        }}
                    >
                        {value.getTitle()}
                    </div>
                ))
            }
        </div>
    );
}

export default App;
// src/App.tsx
profile
Frontend Developer / Amateur Designer

0개의 댓글