본문 바로가기
프론트앤드/[React]

[React] 네이버 지도 API 이용 캐러셀 + center 움직이기

by 헬리이 2023. 3. 31.
728x90

 

 

지난 포스트에 

Marker 누를때 해당 정보를 가진 캐러셀이 맨 첫번 째 슬라이드로 보이게 하는 것을 정리 했었는데 

 

(참고) 

https://hayley-0616.tistory.com/43

 

[React] 네이버 지도 API 이용 + Slick 캐러셀 띄우기

기업협업 중이다.. 여전히 Home을 맡았는데, 홈 자체가 네이버 지도를 불러와서 각각 Marker 를 클릭하면 그 Marker(가게) 의 정보가 담긴 캐러셀이 나오게 해야했다! 처음에 했을때는, Marker를 누르면

hayley-0616.tistory.com

 

 

이번에는, Marker을 눌렀을 때, 해당 데이터 같이 불러오는 캐러셀도 보이기 + 센터 좌표 바뀌기 를 해 보았다. 

 

정리를 또 해 보겠다....

 

이번에도.. 어려웠다... 지도 api.. 정말 쉽지 않군,,,, 😂

 

 

Home.jsx (부모 컴포넌트)

import React, { useEffect, useRef, useState } from 'react';
import HomeCarousel from './HomeCarousel';
import 'slick-carousel/slick/slick.css';
import 'slick-carousel/slick/slick-theme.css';
import Modal from '../Components/Modal/Modal';
import * as S from './Home.style';
import {
  Container as MapDiv,
  NaverMap,
  Marker,
  useNavermaps,
} from 'react-naver-maps';

const Home = () => {

  //MockData시작
  const [homeMartList, setHomeMartList] = useState([]);
  const [selectedMart, setSelectedMart] = useState(null);
  const mapRef = useRef(null);

  const handleMarkerClick = (e, mart) => {
    setSelectedMart(mart);
  };


  const navermaps = useNavermaps();
  const HOME_PATH = window.HOME_PATH || '.';
  const geocoder = navermaps.Service.geocode(
    {
      address: '테헤란로 427',
    },
    function (status, response) {
      if (status !== navermaps.Service.Status.OK) {
        return alert('Something wrong!');
      }
      const result = response.result;
      const items = result.items;
    }
  );
  if (homeMartList.length === 0) return;


useEffect(() => {
    fetch('./data/MhomeData.json')
      .then(response => response.json())
      .then(data => {
        setHomeMartList(data.martList);
      });
  }, []);

  useEffect(() => {
    if (mapRef.current) {
      const newCenter = new navermaps.LatLng(selectedMart.y, selectedMart.x);
      mapRef.current.setCenter(newCenter);
    }
  }, [selectedMart]);
  
  return (
    <S.MapBox>
      <NaverMap
        // defaultCenter={new navermaps.LatLng(centerPoint.y, centerPoint.y)}
        defaultCenter={new navermaps.LatLng(위도, 경도)}
        defaultZoom={15}
        zoomControl={true}
        ref={mapRef}
      >
        {homeMartList.map(mart => {
          return (
            <Marker
              position={new navermaps.LatLng(mart.y, mart.x)}
              key={mart.id}
              icon={{
              onClick={e => handleMarkerClick(e, mart)}
            />
          );
        })}
      </NaverMap>
    </S.MapBox>
  );
};

export default Home;

 

추가가 되었던 로직

  const mapRef = useRef(null);
  const [homeMartList, setHomeMartList] = useState([]);
  const [selectedMart, setSelectedMart] = useState(null);
  
   const handleMarkerClick = (e, mart) => {
    setSelectedMart(mart);
  };
  
  useEffect(() => {
    if (mapRef.current) {
      const newCenter = new navermaps.LatLng(selectedMart.y, selectedMart.x);
      mapRef.current.setCenter(newCenter);
    }
  }, [selectedMart]);

 

🙏🏻 정리해보자 

 

  const mapRef = useRef(null);

: NaverMap 컴포넌트를 참조하는 ref 으로, 초기값을 null 로 설정하였다. 

이때, 인자로 넘어온 초기값을 current  속성에 할당한다. 

 

 

useEffect(() => {
    if (mapRef.current) {
      const newCenter = new navermaps.LatLng(selectedMart.y, selectedMart.x);
      mapRef.current.setCenter(newCenter);
    }
  }, [selectedMart]);

: selectedMart ( Marker눌렀을때 상태가 변화된 변수) 값이 변경될 때 마다 useEffect 가 실행이 된다. 

여기서는, mapRef.current 값이 존재하면 navermaps.LatLng( ) 함수를 사용해서  selectedMart 객체의 좌표 값으로 

새로운 LatLng 객체를 생성한다. (newCenter) 

 

그리고 mapRef.current.setCenter() 매서드를 사용해서 지도의 중심 좌표를 변경하게 되는 로직이다. 

 

즉, handleMarkerClick() 함수에서 선택된 마트 객체인 selectedMart 변수에 저장하면 

useEffect() 함수에서 이 값을 감지해서 

mapRef.current 객체의 setCenter( ) 매서드를 사용해서 선택된 마트 객체 위치로 지도의 중심이 이동되게 된다 !!!!

 

 

 


🙋🏻‍♀️ useRef 란?

 

useRef 함수는 current 속성을 가지고 있는 객체를 반환하는데,

 

인자로 넘어온 초기값을 current 속성에 할당한다.

 

 current 속성은 값을 변경해도 상태를 변경할 때 처럼 React 컴포넌트가 다시 랜더링되지 않는것이 특징이다 !

 

그래서 React 컴포넌트가 다시 랜더링될 때도 마찬가지로 이 current 속성의 값이 유실되지 않는다. 

 

(참조 daleseo.com)

 

 

 

 

 

 

728x90