React + Kakao Map - sdk 활용 예제

sham·2024년 10월 17일
0

SkyScope 개발일지

목록 보기
5/12

다음 토이프로젝트의 개발 기록이다.

Kakao 지도 API, react-kakao-maps-sdk를 사용하였다.

개요

화면 위에 네이버나 카카오 지도를 렌더링하고 싶었다. 고맙게도 네이버, 카카오에서 자기네들의 지도를 활용할 수 있게 API를 제공해주고 있었다.

DOM에 직접 접근해서 세팅하는 방법과 SDK를 사용해서 간단하게 세팅하는 방법 두 가지가 존재하는데, 각각 어떻게 세팅하면 되는지 간단하게 서술하고자 한다.

DOM - index.html에 script 파일 추가

index.html

<!DOCTYPE html>
<html>
<head>
	<meta charset="utf-8"/>
	<title>Kakao 지도 시작하기</title>
</head>
<body>
	<div id="map" style="width:500px;height:400px;"></div>
	<script type="text/javascript" src="//dapi.kakao.com/v2/maps/sdk.js?appkey=발급받은 APP KEY를 넣으시면 됩니다."></script>
	<script>
		var container = document.getElementById('map');
		var options = {
			center: new kakao.maps.LatLng(33.450701, 126.570667),
			level: 3
		};

		var map = new kakao.maps.Map(container, options);
	</script>
</body>
</html>

React SDK - 카카오 맵 sdk 사용

Tutorial | react-kakao-maps-sdk docs

useKakaoLoader.ts

import { useKakaoLoader as useKakaoLoaderOrigin } from "react-kakao-maps-sdk";

export default function useKakaoLoader() {
  useKakaoLoaderOrigin({
    appkey: import.meta.env.VITE_KAKAO_APP_KEY as string,
    libraries: ["clusterer", "drawing", "services"],
  });
}

KakaoMap.tsx

import { Map } from "react-kakao-maps-sdk";
import useKakaoLoader from "@src/useKakaoLoader";

const KaKaoMap = () => {
  useKakaoLoader();

  return (
    <Map
      center={{ lat: 33.5563, lng: 126.79581 }}
      style={{ width: "800px", height: "600px" }}
      level={3}
    />
  );
};

export default KaKaoMap;

활용

react sdk를 세팅한 환경에서 진행했다.

검색어로 검색 & 마커 띄우기 & 마커 정보 기반으로 DIV 만들어서 상호작용을 해보는 예제이다.

다음 사진과 같은 결과를 렌더링하게 된다.

import { useState, useRef, useEffect } from "react";
import { Map, MapMarker } from "react-kakao-maps-sdk";
import useKakaoLoader from "@src/useKakaoLoader";
import { getKakaoLocal } from "@src/API";

import Form from "react-bootstrap/Form";
import styled from "styled-components";

interface MarkerType {
  position: {
    lat: number;
    lng: number;
  };
  content: string;
}

const KaKaoMap = () => {
  useKakaoLoader();

  const [map, setMap] = useState<kakao.maps.Map | null>(null);
  const [info, setInfo]: any = useState();
  const [markers, setMarkers] = useState<MarkerType[]>([]);
  const [mapLevel, setMapLevel] = useState<number>(3);
  const mapRef = useRef<kakao.maps.Map>(null);

  const [address, setAddress] = useState<string>("");

  const handleInput = (e: any) => {
    if (e.key === "Enter") e.preventDefault();
    setAddress(e.target.value);
  };

  const insertAddress = () => {
    searchPlaces(address);
    setAddress("");
  };

  const getInfo = () => {
    const map = mapRef.current;
    if (!map) return;

    const center = map.getCenter();

    console.log("map info ", center);
  };

  const overMarkerPos = (marker: MarkerType) => {
    if (!map) return;

    // 맵 레벨 제어
    const position = marker.position;
    map.setLevel(2);
    setMapLevel(map.getLevel());

    map.panTo(new kakao.maps.LatLng(position.lat, position.lng));

    // region_2depth_name 를 기준으로 검색
    // 스페이스 바 사이의 공백 제거 필요
  };

  const onClickMarker = async (marker: MarkerType) => {
    if (!map) return;
    const position = marker.position;

    const result = await getKakaoLocal.getKakaoSearchCoord(
      position.lng,
      position.lat
    );
  };

  const searchPlaces = (keyword: string) => {
    if (!map) return;
    const ps = new kakao.maps.services.Places();

    ps.keywordSearch(
      keyword,
      (data, status, _pagination) => {
        if (status === kakao.maps.services.Status.OK) {
          // 검색된 장소 위치를 기준으로 지도 범위를 재설정하기위해
          // LatLngBounds 객체에 좌표를 추가합니다
          const bounds = new kakao.maps.LatLngBounds();
          const markers: MarkerType[] = [];
          console.log("data ", data);
          for (let i = 0; i < data.length; i++) {
            // @ts-ignore
            markers.push({
              position: {
                lat: Number(data[i].y),
                lng: Number(data[i].x),
              },
              content: data[i].place_name,
            });
            // @ts-ignore
            bounds.extend(new kakao.maps.LatLng(data[i].y, data[i].x));
          }
          setMarkers([...markers]);

          // 검색된 장소 위치를 기준으로 지도 범위를 재설정합니다
          map.setBounds(bounds);
          console.log("마커 : ", markers);
        } else {
          console.log("검색 결과가 없습니다.");
        }
      },
      { page: 5 }
    );
  };

  return (
    <>
      <Form>
        <Form.Control
          size="lg"
          type="text"
          placeholder="주소 입력"
          value={address}
          onChange={handleInput}
          onKeyDown={handleInput} // Handle key down event
        />
      </Form>
      <button onClick={insertAddress}>확인</button>
      <Map
        center={{
          lat: 37.566826,
          lng: 126.9786567,
        }}
        style={{ width: "800px", height: "600px" }}
        level={mapLevel}
        ref={mapRef}
        onCreate={setMap}
      >
        {markers.map((marker: MarkerType) => (
          <MapMarker position={marker.position} onClick={() => setInfo(marker)}>
            {info && info.content === marker.content && (
              <div>{marker.content}</div>
            )}
          </MapMarker>
        ))}
      </Map>

      {markers.length > 0 && (
        <MarkersContainer>
          {markers.map((marker: MarkerType, index: number) => (
            <div
              key={index}
              onMouseOver={() => overMarkerPos(marker)}
              onClick={() => onClickMarker(marker)}
            >
              {marker.content}
            </div>
          ))}
        </MarkersContainer>
      )}

      <button id="getInfoBtn" onClick={getInfo}>
        맵정보 가져오기
      </button>
    </>
  );
};

export default KaKaoMap;

const MarkersContainer = styled.div`
  display: flex;
  flex-direction: column;
  div {
    cursor: pointer;
    padding: 5px;
    border: 1px solid black;
  }
`;
profile
씨앗 개발자

0개의 댓글

관련 채용 정보