프론트앤드/[React]

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

헬리이 2023. 3. 31. 14:06
728x90

기업협업 중이다.. 여전히

 

Home을 맡았는데, 홈 자체가 네이버 지도를 불러와서

 

각각 Marker 를 클릭하면 그 Marker(가게) 의 정보가 담긴 캐러셀이 나오게 해야했다!

 

 

 

 

처음에 했을때는, Marker를 누르면 해당 정보들은 모두 나오는데, 캐러셀 형태로 나오지않았어서 애를 먹었다...

 

 

 

일단 코드를 보면서 정리를 해 보겠다.

 

 

아직 데이터가 완성되지 않아서 Mock data 를 이용했다.

 

 

 

 

 

 

📌 여기가 부모컴포넌트인 Home 

const Home = () => {


  const [homeMartList, setHomeMartList] = useState([]);
  const [selectedMart, setSelectedMart] = useState(null);

  const handleMarkerClick = (e, mart) => {
    setSelectedMart(mart);
  };
  
  //MockData시작
  useEffect(() => {
    fetch('./data/MhomeData.json')
      .then(response => response.json())
      .then(data => {
        setHomeMartList(data.martList);
      });
  }, []);



  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;


  return (
    <S.MapBox>
      //네이버맵 불러온것
      >
        {homeMartList.map(mart => {
          return (
            <Marker
              position={new navermaps.LatLng(mart.y, mart.x)}
              key={mart.id}
              title={mart.name}
              icon={{
                content: `<S.MarkerBox>
                    <S.MarkerOrder>${mart.name}</S.MarkerOrder>
                    ${mart.phoneNumber}</S.MarkerBox>`,
              }}
              onClick={e => handleMarkerClick(e, mart)}
            />
          );
        })}
//여기가 HomeCarousel을 불러오는 부분!
        <HomeCarousel
          homeMartList={homeMartList}
          selectedMart={selectedMart}
          handleModal={handleModal}
        />
      </NaverMap>
    </S.MapBox>
  );
};

export default Home;

 

//여기가 HomeCarousel을 불러오는 부분!
        <HomeCarousel
          homeMartList={homeMartList}
          selectedMart={selectedMart}
          handleModal={handleModal}
        />

 

- homeMartList : mock데이터를 map을 돌려 setHomeMartList가 상태변화된 것

-selectedMart : Marker을 onClick 했을 때 발생되어 setSelectedMart 의 상태변화 된 것

 

모두 props로 넘겨준다 

 

 

 

 

 

 

📌 자식 컴포넌트 HomeCarousel 

import 'slick-carousel/slick/slick.css';
import 'slick-carousel/slick/slick-theme.css';

const HomeCarousel = ({ homeMartList, selectedMart, handleModal }) => {
  const settings = {
    infinite: true,
    speed: 500,
    slidesToShow: 1,
    slidesToScroll: 1,
    centerMode: true,
    centerPadding: '25px',
    dot: false,
  };
  const [slider, setSlider] = useState(null);
  //처음 화면이 랜더링 되었을때는 null 이라 캐러셀이 보이지 않음 
  
  const smIndex = homeMartList.indexOf(selectedMart);

  const selectedMartList = selectedMart ? homeMartList : [];

  useEffect(() => {
    if (slider) {
      slider.slickGoTo(smIndex);
    }
  }, [smIndex]);

  return (
    <S.CarouselWholeContainer>
      <Slider {...settings} ref={setSlider}>
        {selectedMartList &&
          selectedMartList.map(mart => (
            <S.MartBox key={mart.id} onClick={handleModal}>
             캐러셀 안에 content 작성
            </S.MartBox>
          ))}
      </Slider>
    </S.CarouselWholeContainer>
  );
};

export default HomeCarousel;

 

 

 

 

📍 정리해보겠댜 

<Slider {...settings} ref={setSlider}>

- <Slider> 컴포넌트는 react-slick 패키지에서  이미지나 콘텐츠 등을 슬라이드 형태로 제공하는  컴포넌트 이다.

 

- {...settings} 슬라이드 보여줄 때 사용할 설정 값으로, slick 에서 제공해주고 원하는대로 설정할 수 있다! 

 

나는 dot과 옆에 슬라이드 넘어가는 버튼이 필요없어서 저렇게 했다 ! 

 

 

 

ref = {setSlider} 

여기서 setSlider 는 useState 훅을 사용했다.

const [slider, setSlider] = useState(null);
  //처음 화면이 랜더링 되었을때는 null 이라 캐러셀이 보이지 않음

slider 변수는 <Slider> 컴포넌트의 ref 속성으로 할당되어서 , slider 변수를 사용하여 <Slider> 컴포넌트 메서드를 호출 할 수 있게 했다. 

 

 

 

 

 const smIndex = homeMartList.indexOf(selectedMart);

  const selectedMartList = selectedMart ? homeMartList : [];

  useEffect(() => {
    if (slider) {
      slider.slickGoTo(smIndex);
    }
  }, [smIndex]);

 

const smIndex = homeMartList.indexOf(selectedMart);

smIndex 는 props로 가져온 homeMartList 배열에서 선택된 마트 객체(selectedMart) 가 위치한 index 를 찾는 함수로 로직을 짜 보았다. 

 

 

 

const selectedMartList = selectedMart ? homeMartList : [ ] ;

삼항 연산자를 사용하여, selectedMartList 변수는 선택된 마트가 있으면 homeMartList 배열을 할당하고, 없는경우는 빈 배열을 할당한다는 로직이다. 

 

 

 

  useEffect(() => {
    if (slider) {
      slider.slickGoTo(smIndex);
    }
  }, [smIndex]);

useEffect를 통해 smIndex 값이 변경될 때마다 useEffect가 실행이되고, 

 

이 useEffect 함수 내부에서는 slider 객체가 존재하면

 

slider.slickGoTo( smIndex ) 매서드를 호출해서 선택된 마트가 첫 번째 슬라이드에 위치하도록 설정했다. 

 

 

 

이때, slider 객체는 <Slider> 컴포넌트의 ref 속성을 사용해서 참조한 것이다. 

 

즉, smIndex 값이 변경되서 컴포넌트가 다시 랜더링 될 때마다 실행되고, 

 

slider 객체가 존재할 경우 slickGoTo () 를 실행시켜 슬라이드를 이동시킨다. 

 

 

그래서 이 함수 덕에 마트가 선택되면 smIndex 값이 변경되어서 해당 마트가 첫 번째 슬라이드에 위치하도록 슬라이드를 이동 시키게 된다 !!!!

 

 

 

진짜 짱어렵네... 

 

 

 

slickGoTo가 있는지 처음에 몰랐어서 많이 헤맸다....

 

 

 

 

 

동기의 도움으로 해결했다만..  공식문서 읽는 습관을 좀 가져야 할텐데... 

 


- indexof ( ) 매서드  : 문자열의 위치를 확인하기 위해 씀

이 때, indexOf() 메서드는 대소문자를 구분하고, 일치하는 문자열이 없으면 -1을 반환하니 참고하도록 하자 !!  

728x90