geolocation API로 현 위치 받아오기

수정·2024년 1월 16일
post-thumbnail

지난 프로젝트에서 geolocation API를 이용하여 디바이스의 현 위치를 받아와 그 주위 장소 목록을 반환했다.
오늘은 이 API를 어떻게 이용할 수 있는지에 대해 포스팅 해볼 예정이다.

참고문서: Geolocation API MDN, Geolocation API 사용 예제 MDN


🗺️ geolocation API는 무엇일까?

Geolocation API는 사용 시 사용자의 브라우저가 위치 데이터에 엑세스 할 수 있도록 권한을 요청하게 된다.
사용자가 허용 시 웹 어플리케이션에 자신의 위치를 제공할 수 있게 된다!

주로 사용하게 될 인터페이스는 다음과 같다.

  • Geolocation : 이 기본 클래스는 사용자의 현재 위치를 검색하고, 위치 변경을 감시하면서 이전에 설정된 감시를 지우는 메소드를 가지고 있다.

  • GeolocationPosition : 사용자의 위치를 나타내며 성공 콜백 내부에 포함된 메소드 중 하나에 대한 성공적인 호출에 의해 반환되는 인스턴스다. Geolocation 타임스탬프와 GeolocationCoordinates 객체 인스턴스를 가지고 있다.

  • GeolocationCoordinates : 사용자 위치의 좌표를 나타낸다. 대표적으로 위도, 경도가 있으며 기타 중요한 관련 정보를 갖고 있다.

  • GeolocationPositionError : 해당 인스턴스는 Geolocation 내부 메소드 중 실패한 호출 결과를 에러 메세지와 코드로 반환해준다.

그리고 다른 인터페이스로의 확장이 가능한 방법이 하나 있다.
참고로 나는 현 위치를 받아오는 코드를 작성할 때 이를 활용했다.

Navigator.geolocation

API를 사용할 수 있는 진입점으로, geolocation 객체 인스턴스를 반환하여, 다른 기능들에 접근이 가능하다!

🗺️ 직접 사용해보는 예제

useGeolocation hook을 만들어보자!

사용자의 위치를 파악하여 좌표를 반환해주는 기능을 hook으로 따로 분리하여 사용했다.

import { useEffect, useState } from 'react';

export default function useGeoLocation(options: { timeout: number }) {
  const [location, setLocation] = useState<GeolocationType>({
    latitude: null,
    longitude: null,
    isLoading: true,
  });
  const [error, setError] = useState('');

  const handleSuccess = (pos: GeolocationPosition) => {
    const { latitude, longitude } = pos.coords;

    setLocation({
      latitude,
      longitude,
      isLoading: false,
    });
  };

  const handleError = (err: GeolocationPositionError) => {
    setError(err.message);
  };
}

우선, 현 위치를 받아와 어디인지 마커를 표시해야 했기 때문에 필수적으로 위도와 경도 그리고 로딩 여부가 필요했다.
그리고 3가지의 상태값을 받을 수 있는 location 이란 상태값을 설정했다.

위도와 경도를 처음 null로 설정한 이유는 위도와 경도를 다른 숫자로 줘버리면 아예 이상한 지역으로 핑이 찍힐 수 있을 것 같았다. 그래서 아예 빈 값으로 초깃값을 설정해둔 것이다.

  • handleSuccess : 성공시의 콜백

성공시의 콜백함수에는 GeolocationPosition 타입을 가진 pos라는 파라미터를 받는 것으로 설정해두었다.
그리고 그 pos의 coords가 가진 객체인 latitude, longitude를 받아와 location 상태값에 저장했다.
참고로 위도와 경도값이 새로 들어온다면 로딩은 모두 다 된것으로 판단하여 isLoading은 false 값으로 변경해주었다.

GeolocationPosition 타입에는 읽기 전용의 coords와 timestamp 객체를 갖고 있음을 라이브러리 파일을 통해 알 수 있다.
이는 위 인터페이스 설명에서 작성했기 때문에 다시 위로 올라가 GeolocationPosition 파트를 읽어보면 알 수 있을 것이다!

  • handleError : 실패시의 콜백

위치 변환이 잘 되지 않았을 때는 에러 메세지를 에러 전용 상태값에 저장하도록 했다.

hook 내부의 useEffect 코드

  useEffect(() => {
    const { geolocation } = navigator;

    if (!geolocation) {
      setError('Geolocation을 사용할 수 없어요!');
      return;
    }

    geolocation.getCurrentPosition(handleSuccess, handleError, options);
  }, [options]);

  return { location, error };

위 상태값 설정과 콜백함수들을 만들고나서 useEffect 코드까지 작성해야 현 위치를 받아올 수 있는 hook이 완성된다.

나는 확장가능한 인터페이스 사용을 위해

const { geolocation } = navigator;

navigator가 가진 geolocation 객체를 분해할당하여 불러와 geolocation이 가진 API를 사용할 수 있도록 했다.

만약 geolocation 객체가 인식되지 않는다면 에러 전용 상태값에 해당 API를 사용할 수 없다는 문자를 상태값에 저장했다.
정상적으로 객체가 인식되었다면, getCurrentPosition 메소드를 통해 사용자 디바이스의 현 위치를 받아왔다.

이때 getCurrentPosition 메소드에 넘겨야 하는 인수는 다음과 같다.

  • 첫 번째 인수 : 현 위치 변환 시 성공 콜백
  • 두 번째 인수 : 현 위치 변환 실패 시 실패 콜백
  • 세 번째 인수 : 본인이 설정한 geolocation API 사용시의 옵션

이렇게 useEffect 코드 작성까지 마쳤다면 해당 hook이 위도, 경도와 에러 값을 반환할 수 있도록 return 시켜주면 된다.
나는 location에 위도|경도|로딩 error에 에러문이 담겨있기 때문에 2가지의 상태값만 반환하도록 했다.

🗺️ 만들어둔 geolocation hook을 불러와보자

import { useEffect } from 'react';

const geoLocationOptions = {
	timeout: 6000,
}

const Map = () => {
	const { location } = useGeolocation(geoLocationOptions);
  	const currentLocation = {
    	latitude: location.latitude,
      	longitude: location.longitude,
    }
    
    useEffect(() => {
     	// 우리가 hook 파일의 location 상태값으로 설정해두었던 로딩여부!
		if (!location.isLoading) {
        	window.kakao.maps.load(async () => {
              	// 지도 기본 설정
            	const mapConatiner = document.getElementById('map');
              	const mapOption = {
                	center: new window.kakao.maps.LatLng(
                    	currentLocation.latitude,
                      	currentLocation.longitude,
                    ),
                  	level: 3,
                }
                const map = new window.kakao.maps.Map(mapContainer, mapOption);
              
				// 마커 표시용
              	const coords = new window.kakao.maps.LatLng(
                	currentLocation.latitude,
                  	currentLocation.longitude,
                );
              	const myLocationImageInfo = {
                	imageSrc: 본인의 마커 이미지 파일,
                  	imageSize: new window.kakao.maps.Size(26, 26);
                };
                const myLocationImage = new window.kakao.maps.MarkerImage(
                    myLocationImageInfo.imageSrc,
                    myLocationImageInfo.imageSize,
                    null,
                );
          		const marker = new window.kakao.maps.Marker({
                	position: coords,
                  	image: myLocationImage
                });
          
          		marker.setMap(map);
            })
        }
    }, [location])
  
  return location.isLoading? (
  	<Loading />
  ) : (
  	<>
    	<MapWrap id="map" />
    </>
  )
}

지도 컴포넌트에서 useGeolocation 파일을 불러와 location을 받아왔다.

우리가 hook 내부에서 만들었던 location 상태값에는 latitude, longitude, isLoading 3가지였고, 필요한 것을 추출하여 kakao map API에 적용시켰다.
그리고 사용자의 현 위치를 담은 지도를 표시할 수 있었다.

이렇게 hook으로 만들어 필요한 상태값을 가져와 사용할 수 있기 때문에 본인의 프로젝트 스타일대로 필요한 값을 추가하여 불러와 사용할 수 있다.

🗺️ 결과물

원래는 geolocation API를 사용하기 전, 사용자의 엑세스 권한 허용에 대해 먼저 띄워지고 허용 시 API가 실행된다.
그러나 해당 영상에서는 내가 이미 허용해놓고 여러가지를 촬영했던 영상이라 생략되었다.

원래는 이렇게 위치 허용에 대한 알림이 먼저 뜨고 API 통신이 시작된다😊

profile
💛

0개의 댓글