데브코스 2차 프로젝트 트러블슈팅

2차 프로젝트 트러블 슈팅
프로젝트트러블 슈팅
avatar
2025.02.08
·
7 min read

1. 지도 페이지 첫 검색시 중심을 못잡는 문제

장소 검색 시 해당 장소의 위도와 경도를 이용하여 지도의 정중앙에 위치하도록 구현하고자 하였다.

특정 장소를 검색하였을 때 검색한 장소를 지도의 정중앙에 위치시키도록 하기위해 상태변수 mapInfo 의 상태를 변경해 변경된 mapInfo의 위도 경도 값을 Map 객체의 center 속성안에 할당하는 형식으로 코드를 짰다.

3281
// Map reference

const mapRef = useRef<any>(null);

const map = mapRef.current;



// 지도정보 상태관리

const [mapInfo, setMapInfo] = useState<MapInfo>({

center: {

lat: 37.5666805, // 초기 좌표

lng: 126.9784147,

},

level: 13

});

즉 장소를 검색할때마다 mapInfo는 업데이트 되고 변경된 위도 경도값을 지도의 중심좌표로 설정해주는 것이다.

장소 검색시 mapInfo 상태변수 업데이트

// 검색한 장소로 맵 이동

const handleSelectPlace = (place: Place) => {

setMapInfo((prev) => ({

...prev,

center: { lng: parseFloat(place.x), lat: parseFloat(place.y) },

level: 3,

}));

setSearchResults([]);

};

지도의 중심좌표, 레벨 변경

{/* 지도 */}

<Map

center={mapInfo.center}

level={mapInfo.level}

style={{ width: "100%",

height: "calc(100vh - 180px)",

position: "relative",

overflow: "hidden" }}

ref={mapRef}

>

문제

첫 검색 때 지도의 정중앙을 잡지 못하는 문제 발생

원인

Map 컴포넌트가 리렌더링될 때 mapInfo의 변경된 값을 즉시 반영하지 못하거나, Map 자체가 외부 라이브러리(예: Kakao 지도 API)에 의해 관리되는 DOM 요소라서 React의 상태 변화만으로 그 내부 동작이 완전히 동기화되지 않을 수 있다.

두 번째 검색부터는 잘 되는 이유
첫 번째 검색 시 mapRef로 연결된 Kakao 지도 객체가 mapInfo의 값에 맞춰 설정되지만, 초기에 Kakao 지도 객체와 React 상태 간의 동기화가 완벽하지 않다.

두 번째 검색부터는 Kakao 지도 객체가 이미 초기화된 상태라, React의 setMapInfo 상태 업데이트가 바로 Kakao 지도 객체에 반영된다.

해결
useEffect를 통해 React 상태 변화와 Kakao 지도 객체 상태를 동기화해 주는 방식 사용

useEffect(() => {
    if (!map) return; //Map 객체가 초기화되지 않았을경우 return
    map.setLevel(mapInfo.level); // 지도 레벨 설정
    map.panTo(new kakao.maps.LatLng(mapInfo.center.lat, mapInfo.center.lng)); // 지도 중심을 부드럽게  이동

  }, [mapInfo]);
3288


2. 지도 페이지 캡슐 리스트 최신화 문제

지도의 범위내에 캡슐들이 있으면 캡슐들을 리스트 형태로 보여주는 캡슐리스트를 구현하였다.

지도의 레벨은 장소를 검색하거나 마커 클러스터링을 이용할 때마다 변하는데

이때 지도의 레벨이 바뀔때마다 지도의 범위에 캡슐들이 있다면 이를 리스트 형태로 보여준다.

3287

문제

다른 장소를 검색했을 때 주변에 캡슐들이 있더라도 리스트가 최신화되지 않는다는 문제

원인

지도의 위치가 변경됐을 때 캡슐리스트가 최신화 되지 않았던 이유는 지도의 레벨이 변할때만 캡슐리스트를 최신화 하도록 구현하였기 때문이다.

즉, 지도의 레벨 변화가 없다면 캡슐리스트는 위치에 맞게 최신 정보로 업데이트 되지 않는다.

// 지도의 레벨이 변경될때
  useEffect(() => {
    if (!map) return; //Map 객체가 초기화되지 않았을경우 return
    map.setLevel(mapInfo.level); // 지도 레벨 설정
    map.panTo(new kakao.maps.LatLng(mapInfo.center.lat, mapInfo.center.lng)); // 지도 중심을 부드럽게  이동

    // 지도의 상태가 변경될때마다 실행되는 함수
    const handleMapChange = () => {
      const level = map.getLevel();

      if (level <= 10) {
        // 줌 레벨이 10 이하일 때는 리스트로 표시
        filterChange(level); // 지도 레벨에 따라 캡슐 필터링 함수
        map.setLevel(level);
      }
    };

    if (map) {
      map.addListener("zoom_changed", handleMapChange);

      return () => {
        map.removeListener("zoom_changed", handleMapChange);
      };
    }
  }, [mapInfo, map]);

해결

필터링된 캡슐을 정하기 위해 지도의 레벨이 변경될때마다 실행되는 함수인 handleMapChange가 지도의 레벨 뿐만아니라 중심좌표가 변할때도 캡슐리스트를 최신화할 수 있도록 수정하였다.

handleMapChange가 실행되면 캡슐 마커를 필터링해주는 filterChange 함수를 실행해
필터링된 캡슐들을 캡슐리스트 형태로 보여주었다.

// Map reference
  const mapRef = useRef<any>(null);
  const map = mapRef.current;


 useEffect(() => {
    if (!map) return; //Map 객체가 초기화되지 않았을경우 return
    map.setLevel(mapInfo.level); // 지도 레벨 설정
    map.panTo(new kakao.maps.LatLng(mapInfo.center.lat, mapInfo.center.lng)); // 지도 중심을 부드럽게  이동

    // 지도의 상태가 변경될때마다 실행되는 함수
    const handleMapChange = () => {
      const level = map.getLevel();

      if (level <= 10) {
        // 줌 레벨이 10 이하일 때는 리스트로 표시
        filterChange(level);
        map.setLevel(level);
      }
    };

    if (map) {
      map.addListener("zoom_changed", handleMapChange);
      map.addListener("center_changed", handleMapChange);

      return () => {
        map.removeListener("zoom_changed", handleMapChange);
        map.removeListener("center_changed", handleMapChange);
      };
    }
  }, [mapInfo, map]);

.
.
{/* 지도의 범위에 따라 필터링된 타임캡슐 목록 */}
          {filteredMarkers.length > 0 && (
            <div className="absolute bottom-0 right-0 z-10 w-full max-w-[600px]">
              <div
                className="w-full px-8 overflow-y-auto bg-white dark:bg-gray-600 shadow-lg rounded-t-3xl h-80"
                onClick={(e) => e.stopPropagation()} // 모달 내부 클릭 시 이벤트 전파 방지
              >
                
3289







- 컬렉션 아티클