React로 카카오맵 API 로드하기

안녕하세요 React Component 들을 기반으로 카카오 맵 API를 불러와 카페 웹 지도를 구현 하고자 하는데요 아무리 구글링하여 예제들을 참고하여 지도가 잘 뜨도록 코딩을 해도 생각대로 잘 구현이 되지 않아 Dev Talk에다 질문 글 올립니다 ㅠㅠ

** index.html **

Coffee Maps

** Resume.js **
import React, { Component } from “react”;

class Resume extends Component {
getRandomColor() {
let letters = “0123456789ABCDEF”;
let color = “#”;
for (let i = 0; i < 6; i++) {
color += letters[Math.floor(Math.random() * 16)];
}
return color;
}

render() {
if (!this.props.data) return null;

const skillmessage = this.props.data.skillmessage;
const education = this.props.data.education.map(function(education) {
  return (
    // 카카오맵 API
    <div>
      <div id="map"></div>
      <script type="text/javascript" src="//dapi.kakao.com/v2/maps/sdk.js?appkey=76ca9236bc363cb579d11ca8d617f00b&libraries=services"></script>
      <script src="js/map.js"></script>
    </div>
  );
});

const skills = this.props.data.skills.map(skills => {
  const backgroundColor = this.getRandomColor();
  const className = "bar-expand " + skills.name.toLowerCase();
  const width = skills.level;

  return (
    <li key={skills.name}>
      <span style={{ width, backgroundColor }} className={className}></span>
      <em>{skills.name}</em>
    </li>
  );
});

return (
  <section id="resume">
    <div className="row education">
      <div className="three columns header-col">
        <h1>
          <span>Maps</span>
        </h1>
      </div>

      <div className="nine columns main-col">
        <div className="row item">
          <div className="twelve columns">{education}</div>
        </div>
      </div>
    </div>

    <div className="row skill">
      <div className="three columns header-col">
        <h1>
          <span>Skills</span>
        </h1>
      </div>

      <div className="nine columns main-col">
        <p>{skillmessage}</p>

        <div className="bars">
          <ul className="skills">{skills}</ul>
        </div>
      </div>
    </div>
  </section>
);

}
}

export default Resume;

** Map.js **
import React, { Component } from “react”;
import styled from “styled-components”;

class Maps extends Component {
handleMap = () => {
// 마커를 클릭했을 때 해당 장소의 상세정보를 보여 줄 커스텀 오버레이
var placeOverlay = new kakao.maps.CustomOverlay({zindex: 1}),
contentNode = document.createElement(‘div’),
markers = [],
currCategory = ‘’;

    // 지도를 웹 브라우저 상에 표시할 DOM Element를 지정
    const mapContainer = document.getElementById("map");

    mapOption = { 
        center: new kakao.maps.LatLng(37.20993410884578, 127.05867025427891), // 지도의 중심좌표
        level: 3 // 지도의 확대 레벨
    };

    // 지도를 생성하고 객체(Object)를 DOM에 반환하여 출력
    const map = new kakao.maps.Map(mapContainer, mapOption);

    // 장소 검색 객체를 생성
    var ps = new kakao.maps.services.Places(map);

    // 지도에 idle Event를 등록
    kakao.maps.event.addListener(map, 'idle', searchPlaces);

    // 커스텀 오버레이의 Contents Node에 css class를 추가 
    contentNode.className = 'placeinfo_wrap';

    /* 커스텀 오버레이의 컨텐츠 노드에 mousedown, touchstart 이벤트가 발생했을때
    지도 객체에 이벤트가 전달되지 않도록 이벤트 핸들러로 kakao.maps.event.preventMap 메소드를 등록  */
    addEventHandle(contentNode, 'mousedown', kakao.maps.event.preventMap);
    addEventHandle(contentNode, 'touchstart', kakao.maps.event.preventMap);

    // 커스텀 오버레이 컨텐츠를 설정합니다
    placeOverlay.setContent(contentNode);  

    addCategoryClickEvent();

    // Element에 이벤트 핸들러를 추가시키는 함수
    function addEventHandle(target, type, callback) {
        if (target.addEventListener) {
            target.addEventListener(type, callback);
        } else {
            target.attachEvent('on' + type, callback);
        }
    }

    // 카테고리 검색을 요청하는 함수입니다
    function searchPlaces() {
        if (!currCategory) {
        return;
    }

    placeOverlay.setMap(null);

    removeMarker();

    ps.categorySearch(currCategory, placesSearchCB, {useMapBounds:true}); 
    
    }

    // 장소검색이 완료됐을 때 호출되는 콜백함수 입니다
    function placesSearchCB(data, status, pagination) {
        if (status === kakao.maps.services.Status.OK) {

        // 정상적으로 검색이 완료됐으면 지도에 마커를 표출합니다
        displayPlaces(data);

        } else if (status === kakao.maps.services.Status.ZERO_RESULT) {
            // 검색결과가 없는경우
            alert("해당 지역의 약국 정보 조회 결과가 존재하지 않습니다.");

        } else if (status === kakao.maps.services.Status.ERROR) {
            // 에러로 인해 검색결과가 나오지 않은 경우
            alert("예기지 않은 오류 발생으로 인해 약국 정보 조회 결과를 정상적으로 출력 하는데 실패 하였습니다.");
        }
    }

    // 지도에 마커를 표출하는 함수
    function displayPlaces(places) {
    var order = document.getElementById(currCategory).getAttribute('data-order');

        for ( var i=0; i<places.length; i++ ) {

            // 마커를 생성하고 지도에 표시
            var marker = addMarker(new kakao.maps.LatLng(places[i].y, places[i].x), order);

            /* 마커와 검색결과 항목을 클릭 했을 때
            장소정보를 표출하도록 클릭 이벤트를 추가 */
            (function(marker, place) {
                kakao.maps.event.addListener(marker, 'click', function() {
                    displayPlaceInfo(place);
                });
            })(marker, places[i]);
        }
    }

    // 마커를 생성하고 지도 위에 마커를 표시하는 함수
    function addMarker(position, order) {
    var imageSrc = 'https://t1.daumcdn.net/localimg/localimages/07/mapapidoc/places_category.png', // 마커 이미지 url, 스프라이트 이미지를 씁니다
        imageSize = new kakao.maps.Size(27, 27),  // 마커 이미지의 크기
        imgOptions =  {
            spriteSize : new kakao.maps.Size(72, 206), // 스프라이트 이미지의 크기
            spriteOrigin : new kakao.maps.Point(46, (order*36)), // 스프라이트 이미지 중 사용할 영역의 좌상단 좌표
            offset: new kakao.maps.Point(11, 28) // 마커 좌표에 일치시킬 이미지 내에서의 좌표
        },
    markerImage = new kakao.maps.MarkerImage(imageSrc, imageSize, imgOptions),
        marker = new kakao.maps.Marker({
        position: position, // 마커의 위치
        image: markerImage 
    });

    marker.setMap(map);
    markers.push(marker);

    return marker;
    }

    // 지도 위에 표시되고 있는 마커를 모두 제거합니다
    function removeMarker() {
    for ( var i = 0; i < markers.length; i++ ) {
        markers[i].setMap(null);
    }

    markers = [];
    }

    // 클릭한 마커에 대한 장소 상세정보를 커스텀 오버레이로 표시하는 함수
    function displayPlaceInfo (place) {
    var content = '<div class="placeinfo">' +
        '   <a class="title" href="' + place.place_url + '" target="_blank" title="' + place.place_name + '">' + place.place_name + '</a>';   

    if (place.road_address_name) {
        content += '    <span title="' + place.road_address_name + '">' + place.road_address_name + '</span>' +
            '  <span class="jibun" title="' + place.address_name + '">(지번 : ' + place.address_name + ')</span>';
    }  else {
        content += '    <span title="' + place.address_name + '">' + place.address_name + '</span>';
    }                

    content += '    <span class="tel">' + place.phone + '</span>' + 
        '</div>' + 
        '<div class="after"></div>';
        contentNode.innerHTML = content;
        placeOverlay.setPosition(new kakao.maps.LatLng(place.y, place.x));
        placeOverlay.setMap(map);  
    }


    // 각 카테고리에 클릭 이벤트를 등록
    function addCategoryClickEvent() {
    var category = document.getElementById('category'),
      children = category.children;

        for (var i=0; i<children.length; i++) {
            children[i].onclick = onClickCategory;
        }
    }

    // 카테고리를 클릭했을 때 호출되는 함수입
    function onClickCategory() {
    var id = this.id,
    className = this.className;

    placeOverlay.setMap(null);

        if (className === 'on') {
            currCategory = '';
            changeCategoryClass();
            removeMarker();
        } else {
            currCategory = id;
            changeCategoryClass(this);
            searchPlaces();
        }
    }

    // 클릭된 카테고리만 클릭된 스타일을 적용하는 함수
    function changeCategoryClass(el) {
    var category = document.getElementById('category'),
        children = category.children,
        i;

    for ( i=0; i<children.length; i++ ) {
        children[i].className = '';
    }

        if (el) {
            el.className = 'on';
        } 
    } 

    /* 지도상 컨트롤 메뉴 삽입
    일반 지도와 스카이 뷰 지도 타입으로 변경 할 수 있는 지도 타입 컨트롤 추가 */
    const mapTypeControl = new kakao.maps.MapTypeControl();

    // 컨트롤을 추가하고자 하는 지도를 지정
    map.addControl(mapTypeControl, kakao.maps.ControlPosition.TOPRIGHT);

    // 지도 Zoom-In, Zoom-Out 기능을 지원하는 Zoom 컨트롤 추가
    const zoomControl = new kakao.maps.ZoomControl();
    map.addControl(zoomControl, kakao.maps.ControlPosition.RIGHT);

    // 좌표 정보를 주소로 변환
    // 좌표 정보를 주소로 변환하는 객체를 생성
    var geocoder = new kakao.maps.services.Geocoder();
    var marker = new kakao.maps.Marker();
    infowindow = new kakao.maps.InfoWindow({zindex: 2});

    // 현재 지도 중심좌표로 주소를 검색해서 지도 좌측 상단에 표시
    searchAddrFromCoords(map.getCenter(), displayCenterInfo);

    /* 지도 클릭시 클릭한 지점의 위치 자표를 주소 정보롤 변환시켜
    브라우저 상에 보여지도록 하는 이벤트를 추가 */
    kakao.maps.event.addListener(map, 'click', function(mouseEvent) {
        searchDetailAddrFromCoords(mouseEvent.latLng, function(result, status) {
            if (status === kakao.maps.services.Status.OK) {
                var detailAddr = !!result[0].road_address ? '<div>도로명주소 : ' + result[0].road_address.address_name + '</div>' : '';
                detailAddr += '<div>지번 주소 : ' + result[0].address.address_name + '</div>';
                
                var content = '<div class="bAddr">' +
                                '<span class="title">법정동 주소정보</span>' + 
                                detailAddr + 
                            '</div>';

                // 마커를 클릭한 위치에 표시합니다 
                marker.setPosition(mouseEvent.latLng);
                marker.setMap(map);

                // 인포윈도우에 클릭한 위치에 대한 법정동 상세 주소정보를 표시합니다
                infowindow.setContent(content);
                infowindow.open(map, marker);
            }
        });
    });

    // 중심 좌표나 확대 수준이 변경됐을 때 지도 중심 좌표에 대한 주소 정보를 표시하도록 이벤트를 등록합니다
    kakao.maps.event.addListener(map, 'idle', function() {
        searchAddrFromCoords(map.getCenter(), displayCenterInfo);
    });

    function searchAddrFromCoords(coords, callback) {
        // 좌표로 행정동 주소 정보를 요청합니다
        geocoder.coord2RegionCode(coords.getLng(), coords.getLat(), callback);         
    }

    function searchDetailAddrFromCoords(coords, callback) {
        // 좌표로 법정동 상세 주소 정보를 요청합니다
        geocoder.coord2Address(coords.getLng(), coords.getLat(), callback);
    }

    // 지도 좌측상단에 지도 중심좌표에 대한 주소정보를 표출하는 함수입니다
    function displayCenterInfo(result, status) {
        if (status === kakao.maps.services.Status.OK) {
        var infoDiv = document.getElementById('centerAddr');

        for(var i = 0; i < result.length; i++) {
            // 행정동의 region_type 값은 'H' 이므로
            if (result[i].region_type === 'H') {
                infoDiv.innerHTML = result[i].address_name;
                break;
            }
        }
    }
}

}

render() {
    <div className="Mapwrap">
        <div id="Map"></div>
    </div>
}

}
export default Maps;

리액트 예제 링크입니다.
참고해서 구현해주세요.
https://codesandbox.io/s/gifted-wescoff-77nwu

1개의 좋아요

답변 감사합니다!! ㅎㅎ

1개의 좋아요