[LG CNS AM Inspire Camp 1기] React (14) - [LAB] 근처 카페 검색 웹 어플리케이션 끄적이기 (3)

정성엽·2025년 1월 12일
0

LG CNS AM Inspire 1기

목록 보기
24/53
post-thumbnail

INTRO

이전 포스팅에서 Naver Search API를 사용하여 검색 훅을 만들어봤다.

이제는 지금까지 만든 내용을 응용하여 주소를 입력하면 근처 카페를 검색해주는 웹 어플리케이션을 만들어보자


11. 동작 순서

이제 내가 만들려는 웹 어플리케이션의 동작 순서를 생각해보면 다음과 같다.

동작 순서
Naver Map API로 현재 주소 파싱 -> 현재 주소를 기준으로 근처 카페 검색 -> 검색된 카페들을 배열로 저장 (좌표값 O) -> Naver Map API로 뿌려주기 -> 내가 편한 UI로 구성


12. 검색 활용

우선 검색 API부터 근처 지역의 지점을 검색하도록 수정해보자

searchLocal.js

import searchInstance from "./searchInstance";

export const searchLocal = async (query) => {
  try {
    const response = await searchInstance.get("/v1/search/local.json", {
      params: { query, display: 5 },
    });
    return response.data;
  } catch (error) {
    console.error("Error : ", error);
    throw error;
  }
};

여기서 아쉬운게 하나 있다면 해당 API를 통해 검색되는 결과가 최대 5개까지 밖에 없다는 것이다.

(이 부분 떄문에 내가 원하는 완벽한 어플리케이션을 만들진 못했다)

다음으로 이 searchLocal API를 사용해서 검색 결과를 추가하는 코드를 작성하자

Naver Map.jsx에 추가된 부분

 useEffect(() => {
    const timer = setTimeout(() => {
      naver.maps.Service.reverseGeocode(
        {
          location: new naver.maps.LatLng(address.y, address.x),
        },
        function (status, res) {
          if (status !== naver.maps.Service.Status.ERROR) {
            if (res.result.items.length > 0) {
              const item = res.result.items[0];
              const address = item.address;
              const roadAddress = item.roadAddress;

              const fetchCafes = async () => {
                const res = await searchLocal(
                  `${roadAddress || address} 근처 카페`
                );
                console.log(
                  res.items.filter((item) => item.category.includes("음식점"))
                );
              };

              fetchCafes();

              console.log("현재 위치 주소:", roadAddress || address);
            }
          } else {
            alert("주소를 찾을 수 없습니다");
          }
        }
      );
    }, 300);

    return () => clearTimeout(timer);
  }, [address]);

우선 동작하는걸 목표로 코드를 작성했기 때문에 정리가 안된 코드이다. (오히려 더 직관적일수도?)

동작 순서를 살펴보면 .reverseGeocode를 사용해서 현재 저장된 좌표값을 주소로 변경한다.

res에 넘어온 주소값을 사용하여 ${roadAddress || address} 근처 카페 라는 쿼리를 생성하고, 이전에 만든 searchLocal을 사용하여 검색을 시도한다.

검색어를 정리해보면 서울특별시 OO구 OO동 123-11 근처 카페 이런식으로 되는 것이다.

그다음으로 콘솔에 찍어보니 무슨 스터디카페도 넘어오는걸 확인할 수 있었다.

그래서 filter로 카테고리를 제한하고 콘솔에 찍어봤다.

Console View

제대로 검색되는 모습을 볼 수 있다

이제 이 값들을 배열에 저장해서 Naver Map API로 넘겨주면 될 것이다.


13. 마커 추가

Naver Map API로 넘겨준다는 것은 지도에 마커를 표시한다는 걸 의미한다.

따라서 마커를 생성하는 로직을 추가해보자

NaverMap.jsx 추가된 부분 (1)

const [cafes, setCafes] = useState([]);

...
const fetchCafes = async () => {
  const res = await searchLocal(
    `${roadAddress || address} 근처 카페`
  );
  const filteredCafe = res.items
  .filter((item) => item.category.includes("음식점"))
  .map((item) => {
    const point = new naver.maps.Point(
      parseFloat(item.mapx) / 10000000,
      parseFloat(item.mapy) / 10000000
    );
    return { ...item, mapx: point.x, mapy: point.y };
  });
  console.log(filteredCafe);
  setCafes(filteredCafe);
};

우선 기존 로직에서 cafes를 관리하는 상태변수를 추가해주자
다음으로 검색 결과를 파싱해서 이 상태변수에 저장하면 된다.

이 때, 넘어오는 좌표값이 float이 아니라 Integer이므로 10000000으로 나눠서 우리가 사용할 값으로 만들어서 넘겨주자

NaverMap.jsx 추가된 부분 (2)

useEffect(() => {
  cafes.forEach((cafe) => {
    addMarker(cafe.title, cafe.mapx, cafe.mapy);
  });
}, [cafes]);

const addMarker = (name, lat, lng) => {
  let newMarker = new naver.maps.Marker({
    position: new naver.maps.LatLng(lng, lat),
    map: mapInstance.current,
    title: name,
    clickable: true,
  });
  newMarker.setTitle(name);
};

naver API를 사용해서 마커를 추가하는 addMarker를 정의하고, 상태변수로 관리하는 cafes가 변경될 때마다 루프를 돌며 지도에 마커를 추가하도록 코드를 작성했다.

Result View


14. 상세 정보 보여주기

위 상태에서 추가해야하는 것은 마커를 클릭했을 때 가게의 상세 정보를 보여줄 수 있도록 해야한다.

이 부분을 구현하기 위해 클릭한 카페 정보를 상태 변수로 저장하고, 조건부 렌더링으로 클릭한 카페의 상세 정보를 표현해주려고 했다.

NaverMap.jsx 추가된 부분

const [selectedCafe, setSelectedCafe] = useState(null);
...
const addMarker = (name, lat, lng, cafe) => {
  let newMarker = new naver.maps.Marker({
    position: new naver.maps.LatLng(lng, lat),
    map: mapInstance.current,
    title: name,
    clickable: true,
  });
  newMarker.setTitle(name);
  naver.maps.Event.addListener(newMarker, "click", function (e) {
    setSelectedCafe(cafe); 
  });
};
...
return (
  <div>
    <div ref={mapElement} style={{ width: "100%", height: 400 }}>
      NaverMap
    </div>
    {selectedCafe && (
      <div>
        ...{카페 상세 정보 표시}
      </div>
    )}
  </div>
);

naver API를 사용해서 클릭 이벤트 발생시 selectedCafe에 해당 카페가 저장되도록 수정했다.

return 부분을 살펴보면 조건부 렌더링으로 카페 상세 내용이 보여지도록 수정했다.

(카페 정보를 보여주는 코드는 UI 부분이라 생략)


OUTRO

지금까지 정리한 내용을 보니 Naver API를 내가 어떻게 사용했는지를 정리한 느낌이다.

사실 블로그 포스팅을 쓴 이유는 이 뭉텅이로 존재하는 코드를 어떤 아이디어로 리팩토링을 수행했는지를 정리하기 위해서였다.

그 내용은 다음 포스팅에서 정리해볼 예정이다.


참고
NaverMaps Tutorial

profile
코린이

0개의 댓글

관련 채용 정보