[react] 카카오맵 사용 시 메모리 누수 잡기

·2024년 9월 27일
0

개발 기록

목록 보기
65/68

문제

카카오맵을 사용하는 부분에서 메모리가 터지는 에러를 발견했다.

기존 코드를 살펴보니 useEffect 내부에 카카오맵 객체를 생성하는 코드가 모두 함께 있었다.

그리고 의존성 배열에 값을 추가해 사용자 입력값이 바뀌면 useEffect가 재실행 되면서 매번 객체가 생성되도록 작성되어 있었다. 언마운트 할 때 참조 해제도 되어있지 않았다.

  useEffect(() => {
    const kakao = (window as any).kakao;

    if (!kakao) return;

    kakao.maps.load(function () {
      // 주소-좌표 변환 객체 생성
      const geocoder = new kakao.maps.services.Geocoder();

      const mapContainer = document.getElementById(''),

      // 지도 생성
      const map = new kakao.maps.Map(mapContainer!, mapOption);

      const renderMap = () => {
        //좌표 생성
        const coords = new kakao.maps.LatLng(latitude, longitude);

        // 표시할 마크 생성
        const marker = new kakao.maps.Marker({});

        // 장소 인포 생성
        const infowindow = new kakao.maps.InfoWindow({});
        infowindow.open(map, marker);
		};
    });
  }, [a, b, c]);

입력이 바뀔 때마다 무한 생성 중...

수정 1

지도 객체를 여러 번 생성할 필요가 없었기 때문에 useRef로 객체를 저장하고 의존성 배열을 비워 한 번만 생성되도록 코드를 수정했다.

  const infoWindow = useRef<kakao.maps.InfoWindow | null>(null);
  const marker = useRef<kakao.maps.Marker | null>(null);
  const map = useRef<kakao.maps.Map | null>(null);
  const coords = useRef<kakao.maps.LatLng | null>(null);
  const zoomControl = useRef<kakao.maps.ZoomControl | null>(null);
  const mapContainer = useRef<HTMLDivElement>(null);
  
 useEffect(() => {
    if (!window.kakao) return;

    window.kakao.maps.load(() => {
      const MapContainer = mapContainer.current;

      coords.current = new kakao.maps.LatLng();
      marker.current = new window.kakao.maps.Marker();
      infoWindow.current = new window.kakao.maps.InfoWindow();
      map.current = new window.kakao.maps.Map();
      zoomControl.current = new kakao.maps.ZoomControl();
    });

    return () => {
      marker.current?.setMap(null);
      infoWindow.current?.close();
      marker.current = null;
      map.current = null;
      infoWindow.current = null;
    };
  }, []);

수정 2

메모리 누수가 발생하던 코드는 입력값이 바뀌면 카카오맵과 관련된 모든 객체를 새로 생성하도록 되어있었다.
카카오맵에서 제공되는 api로 객체를 새롭게 생성할 필요 없이 값을 변경할 수 있다.

그래서 api들을 사용하고 각각의 입력값 별로 useEffect를 분리해 동작할 수 있게 수정했다.

  useEffect(() => {
    if (name && map.current && infoWindow.current) {
      infoWindow.current?.setContent(infoWindowTemplate(name));
    }
  }, [name]);

  useEffect(() => {
    if (level && map.current) {
      map.current?.setLevel(level);
    }
  }, [level]);

  useEffect(() => {
    if (coordinates && map.current && marker.current && infoWindow.current) {
      const moveLatLon = new kakao.maps.LatLng(
        coordinates.latitude,
        coordinates.longitude,
      );
      map.current?.setCenter(moveLatLon);
      marker.current?.setPosition(moveLatLon);
      infoWindow.current?.open(map.current, marker.current);
    }
  }, [coordinates]);

0개의 댓글