다양한 이미지 마커 표시하기 예제 React 구현시 클릭이벤트 질문입니다

다양한 이미지 마커 표시하기 예지를 react로 구현하는데
편의점이나 커피숍 클릭 이벤트가 작동 안합니다.

document.getElementById , document.getElementByClassName 다 써봤는데 혹시 어떻게 해야 되나요?

image

import React, { useEffect } from 'react';
import './MapContainer.css';

const { kakao } = window;



const MapContainer = () => {

    useEffect(() => {
      const container = document.getElementById("map");
      const options = {
        center: new kakao.maps.LatLng(37.499590490909185, 127.0263723554437), //좌표 (y,x) 37.5077381724771, 127.034315435567
        level: 3,
      };
      const map = new kakao.maps.Map(container, options);

      var coffeePositions = [ 
        new kakao.maps.LatLng(37.499590490909185, 127.0263723554437),
        new kakao.maps.LatLng(37.499427948430814, 127.02794423197847),
        new kakao.maps.LatLng(37.498553760499505, 127.02882598822454),
        new kakao.maps.LatLng(37.497625593121384, 127.02935713582038),
        new kakao.maps.LatLng(37.49646391248451, 127.02675574250912),
        new kakao.maps.LatLng(37.49629291770947, 127.02587362608637),
        new kakao.maps.LatLng(37.49754540521486, 127.02546694890695)                
    ];

    var storePositions = [
      new kakao.maps.LatLng(37.497535461505684, 127.02948149502778),
      new kakao.maps.LatLng(37.49671536281186, 127.03020491448352),
      new kakao.maps.LatLng(37.496201943633714, 127.02959405469642),
      new kakao.maps.LatLng(37.49640072567703, 127.02726459882308),
      new kakao.maps.LatLng(37.49640098874988, 127.02609983175294),
      new kakao.maps.LatLng(37.49932849491523, 127.02935780247945),
      new kakao.maps.LatLng(37.49996818951873, 127.02943721562295)
  ];
      
    var markerImageSrc = 'https://t1.daumcdn.net/localimg/localimages/07/mapapidoc/category.png';  // 마커이미지의 주소입니다. 스프라이트 이미지 입니다
    var coffeeMarkers = [], // 커피숍 마커 객체를 가지고 있을 배열입니다
        storeMarkers = []; // 편의점 마커 객체를 가지고 있을 배열입니다

        createCoffeeMarkers();
        createStoreMarkers();
        changeMarker('coffee');
        
  
      function createMarkerImage(src, size, options) {
        var markerImage = new kakao.maps.MarkerImage(src, size, options);
        return markerImage;            
      }

      //마커 만들기
      function createMarker(position, image) {
        var marker = new kakao.maps.Marker({
            position: position, 
            image: image
        });
        
        return marker;  
      }   
      
      //커피
      function createCoffeeMarkers() {
        for (var i = 0; i < coffeePositions.length; i++) {  
            var imageSize = new kakao.maps.Size(22, 26),
                imageOptions = {  
                    spriteOrigin: new kakao.maps.Point(10, 0),    
                    spriteSize: new kakao.maps.Size(36, 98)  
                };     
            
            // 마커이미지와 마커를 생성합니다
            var markerImage = createMarkerImage(markerImageSrc, imageSize, imageOptions),    
                marker = createMarker(coffeePositions[i], markerImage);  
            
            // 생성된 마커를 커피숍 마커 배열에 추가합니다
            coffeeMarkers.push(marker);
        }
      }     

        function setCoffeeMarkers(map) {        
          for (var i = 0; i < coffeeMarkers.length; i++) {  
              coffeeMarkers[i].setMap(map);
          }        
      }

      //편의점
      function createStoreMarkers() {
        for (var i = 0; i < storePositions.length; i++) {
          var imageSize = new kakao.maps.Size(22, 26),
            imageOptions = {
              spriteOrigin: new kakao.maps.Point(10, 36),
              spriteSize: new kakao.maps.Size(36, 98),
            };

          // 마커이미지와 마커를 생성합니다
          var markerImage = createMarkerImage(
              markerImageSrc,
              imageSize,
              imageOptions
            ),
            marker = createMarker(storePositions[i], markerImage);

          // 생성된 마커를 편의점 마커 배열에 추가합니다
          storeMarkers.push(marker);
        }
      }

      function setStoreMarkers(map) {        
        for (var i = 0; i < storeMarkers.length; i++) {  
            storeMarkers[i].setMap(map);
        }        
    }
    
    function changeMarker(type){
    
        var coffeeMenu = document.getElementById('coffeeMenu');
        var storeMenu = document.getElementById('storeMenu');
        
        // 커피숍 카테고리가 클릭됐을 때
        if (type === 'coffee') {
    
          // 커피숍 카테고리를 선택된 스타일로 변경하고
          coffeeMenu.className = 'menu_selected';
          
          // // 편의점과 주차장 카테고리는 선택되지 않은 스타일로 바꿉니다
          storeMenu.className = '';
          
          // 커피숍 마커들만 지도에 표시하도록 설정합니다
          setCoffeeMarkers(map);
          setStoreMarkers(null);
          
      } else { // 편의점 카테고리가 클릭됐을 때
      
          // 편의점 카테고리를 선택된 스타일로 변경하고
          coffeeMenu.className = '';
          storeMenu.className = 'menu_selected';
          
          // 편의점 마커들만 지도에 표시하도록 설정합니다
          setCoffeeMarkers(null);
          setStoreMarkers(map);
          
      } 
    } 



     
    //useEffect  
    }, []);

    
    return (
      <React.Fragment>
        <div id="map" style={{ width: "100%", height: "40vw" }}></div>
        <div class="category">
        <ul>
            <li id="coffeeMenu" onclick="changeMarker('coffee')">
                <span class="ico_comm coffee"></span>
                커피숍
            </li>
            <li id="storeMenu" onclick="changeMarker('store')">
                <span class="ico_comm ico_store"></span>
                편의점
            </li>
        </ul>
    </div>
      </React.Fragment>
    );
}

export default MapContainer;

우선 해당 문제는… 지도 SDK와는 직접적으로 관련이 없다고 판단됩니다.
리액트를 사용하는 방법에 대한 질문에 해당된다고 보는데요.
저희가 자세히 답변드릴 사항은 아니란 점 먼저 알아주시고, 답변에 양해 부탁드립니다.

react component에 기술하는 JSX에는 class 대신 className prop을 사용하며
이벤트 처리도 약간 다릅니다. https://ko.reactjs.org/docs/handling-events.html

<Element class="a" onclick="handler"></Element> // (X)
<Element className="a" onClick={handler}></Element> // (O)

위는 단순히 보이는 코드에 대한 내용일 뿐이고 실제 작성하신 코드의 문제는 따로 있습니다.

예제의 상황에서는 엘리먼트를 특정하기 위해서 ID 부여 후 document.getElementById 를 사용하는데
리액트에서는 그렇게 사용하지 않는 것이 좋습니다.

  1. ID값이 문서 내에서 유일하다는 보장이 없고
  2. 그렇게 셀렉팅하여 엘리먼트를 조작하게 되면, 단방향 데이터 흐름을 가진 리액트 렌더링 라이프 사이클에서 벗어나게 되기 때문에 부작용에 대한 관리의 어려움이 생기게 되고 경우에 따라서는 성능에 영향을 줄 수도 있습니다.

ref를 사용하여 DOM을 직접 접근할 수도 있지만 이것도 어쩔 수 없을 경우에 사용하는 것이지 추천하지 않습니다.
일반적인 상황에서 상태 처리는 개별 컴포넌트가 가지고 있는 state와 prop의 참조로 해결되기 때문입니다.

상태의 변화와 전파가 필요하다면 해당 영역을 컴포넌트로 만드세요.
그리고 상태 처리 핸들러를 만들어서 컴포넌트를 조작하고 필요하면 상태 관리를 상위 컴포넌트에 위임하세요.
이렇게 쌓아나가는 것이 리액트로 앱을 구축하는 과정입니다.

1개의 좋아요

답변 감사합니다. 지도 API와 벗어난 질문을 드려 죄송합니다 ㅜㅜ

useEffect안에 다 때려넣는게 아니라 나눴어야 됐군요 개념이 미흡했습니다.