[TIL #65] 카카오지도 Geocoder에러

차슈·2024년 8월 7일
0

TIL

목록 보기
65/70
post-thumbnail

카카오 지도 사용하기

kakao developers에 가서 -> 내가 만든 애플리케이션을 클릭! -> 앱 설정 -> 앱키 -> Javascript키를 복사하여 env.local에 넣어주고 시작해야한다.

이 과정을 했다면 다음은 공식문서 살펴보면 된다.


트러블슈팅

카카오 지도를 사용하는데, 지도가 잘 나오다가 새로고침을 하니 이런 에러가 발생했다.

찾아보니, Kakao Maps SDK가 제대로 로드되지 않았거나, window.kakao.maps.services.Geocoder가 정의되지 않은 상태에서 사용하려고 했기 때문에 발생할 수 있다고 한다.

일단, 주소를 받아와서 위도와 경도를 쓰기때문에 libraries=services를 추가해줘야한다.

처음 코드

'use client ';
const KAKAO_SDK_URL = https://dapi.kakao.com/v2/maps/sdk.js?appkey=${process.env.NEXT_PUBLIC_KAKAO_API_KEY}&libraries=services,clusterer&autoload=false;

const KaKaomap = () => {
  const { id } = useParams<{ id: string }>();
  const [scriptLoad, setScriptLoad] = useState<boolean>(false);
  const [location, setLocation] = useState<{ lat: number; lng: number } | null>(
    null
  );

  useEffect(() => {
    const loadMap = () => {
      const script = document.createElement('script');
      script.async = true;
      script.src = KAKAO_SDK_URL;
      script.onload = () => {
        setScriptLoad(true);
      };
      document.head.appendChild(script);
    };

    const fetchData = async () => {
      try {
        const response = await fetch(/api/market/map?id=${id});
        const { data } = await response.json();

        console.log('도로명주소', data.도로명주소);

        if (data && data.도로명주소) {
          // Kakao Maps SDK가 로드된 후 지오코더를 사용해 주소를 좌표로 변환
          if (window.kakao && window.kakao.maps) {
            console.log(1);
            const geocoder = new window.kakao.maps.services.Geocoder();
            geocoder.addressSearch(data.도로명주소, (result, status) => {
              console.log(1.1);
              if (
                status === window.kakao.maps.services.Status.OK &&
                result[0]
              ) {
                console.log(2);
                const coords = {
                  lat: parseFloat(result[0].y),
                  lng: parseFloat(result[0].x)
                };
                console.log('좌표', coords);
                setLocation(coords);
              }
            });
          }
        }
      } catch (error) {
        console.error('지도 불러오기 에러 ', error);
      }
    };

    loadMap();
    fetchData();
  }, [id]);

export default KaKaomap;

현재 코드에서는 SDK를 로드한 직후에 바로 fetchData 함수를 호출하는 형태이다. 그러나 스크립트가 로드되었다고 해서 즉시 window.kakao.maps가 사용 가능한 상태가 되는 것은 아니기때문에 load의 상태 확인이 필요하다.

그렇기 때문에 scriptLoad 상태가 true가 되었을 때 fetchData를 호출해야한다. 그 다음 SDK를 로드 하고 kakao.map을 호출하여 초기화해야 각각 원하는 주소 별로 위도와 경도가 찍힌다.

수정코드


const KaKaomap = () => {
  const { id } = useParams<{ id: string }>();
  const [kakaoMapsLoaded, setKakaoMapsLoaded] = useState(false);
  const [location, setLocation] = useState<{ lat: number; lng: number } | null>(
    null
  );

  useEffect(() => {
    const loadKakaoMaps = () => {
      const script = document.createElement('script');
      script.async = true;
      script.src = KAKAO_SDK_URL;
      script.onload = () => {
        window.kakao.maps.load(() => {
          setKakaoMapsLoaded(true);
        });
      };
      document.head.appendChild(script);
    };

    loadKakaoMaps();
  }, []);

  useEffect(() => {
    const fetchData = async () => {
      if (!kakaoMapsLoaded) return;

      try {
        const response = await fetch(`/api/market/map?id=${id}`);
        const { data } = await response.json();

        if (data && data.도로명주소) {
          const geocoder = new window.kakao.maps.services.Geocoder();
          geocoder.addressSearch(data.도로명주소, (result, status) => {
            if (status === window.kakao.maps.services.Status.OK && result[0]) {
              const coords = {
                lat: parseFloat(result[0].y),
                lng: parseFloat(result[0].x)
              };
              setLocation(coords);
            }
          });
        }
      } catch (error) {
        console.error('지도 불러오기 에러 ', error);
      }
    };

    fetchData();
  }, [id, kakaoMapsLoaded]);

  if (!kakaoMapsLoaded || !location) {
    return <div>Loading...</div>;
  }
};

export default KaKaomap;

Kakao Maps SDK 로딩과 초기화를 별도의 useEffect에서 처리했다.
SDK가 완전히 로드되고 초기화된 후에만 fetchData를 실행시켜서 데이터를 가져오게 수정하였다.

SDK가 완전히 로드되고 초기화된 후에만 지오코딩 기능을 사용하기 때문에 타입에러가 나오지 않았다.

원인

Kakao Maps SDK의 로딩 타이밍과 사용 타이밍이 맞지 않았던 것 같다.외부 스크립트를 로드할 때, 스크립트가 DOM에 추가되는 것과 실제로 실행되어 전역 객체(window.kakao)를 설정하는 것 사이에는 시간 차이가 있을 수 있기 때문에 useEffect를 분리해줄때, 원하는 값을 얻을 수 있을 것이다.

카카오맵 api 공식문서
카카오맵 document 공식문서

0개의 댓글