본문 바로가기
웹 프론트엔드/React

React 에서 geolocation API를 hook 으로 만들어 써보기

by 번데기 개발자 2021. 11. 3.
반응형

React에서의 GeoLocation

 

GeoLocation은 GPS 또는 네트워크를 이용하여 현재 위치 정보를 반환하는 API입니다.

 

즉 웹브라우저에서 현재 내 위치의 위도(latitude)와 경도(longitude)를 알아보고 싶을때 주로 사용합니다.

 

저는 React 프로젝트에서 해당 기능을 쓰고 싶어서 이를 React로 구현할 수 있는 방법을 찾아보았습니다.

 

 

GeoLocation의 함수

 

Geolocation 함수는 보통 Javascript에서 window의 navigator.geolocation 객체를 통해 사용할 수 있는데요,

 

먼저 GeoLocation의 함수에 대해서 간단히 살펴보면 아래와 같습니다.

 

clearWatch

  • WatchPosition을 멈춘다.

getCurrentPosition

  • 현재 위치를 가져온다.

watchPosition

  • 지정된 시간마다 현재 위치를 가져온다. (실시간으로 위치가 변할때)

 

좀더 자세하게 알아보고 싶으시면 아래 mdn 문서를 참고하시면 됩니다.

 

https://developer.mozilla.org/ko/docs/Web/API/Geolocation_API/Using_the_Geolocation_API

 

Geolocation API 사용하기 - Web API | MDN

Geolocation API는 navigator.geolocation 객체를 통해 사용할 수 있습니다.

developer.mozilla.org

 

 

Geolocation hooks로 사용해보기

 

Geolocation에 대해 검색을 하던 중에 hooks로 구현되어 있는 GeoLocation을 만든 github repository를 찾을수 있었습니다.

 

https://github.com/NorbertB29/geolocation-api-hook/tree/215f81d1438d617ecdf4a2f1fb7a067228ceb5f8

 

GitHub - NorbertB29/geolocation-api-hook: Using HTML Geolocation API with React Hooks example

Using HTML Geolocation API with React Hooks example - GitHub - NorbertB29/geolocation-api-hook: Using HTML Geolocation API with React Hooks example

github.com

위 Repository의 src/hooks 폴더를 살펴보면 useCurrentLocation, useWatchLocation 라는 이름을 가진 hooks들을 찾을수 있습니다.

 

위 Hooks들을 어떻게 사용하는지 간단하게 살펴보겠습니다.

 

 

useCurrentLocation Hook으로 한번만 내위치 불러오기

// src/hooks/useCurrentPosition.js

import { useState, useEffect } from "react";

const useCurrentLocation = (options = {}) => {
  // location 정보 저장
  const [location, setLocation] = useState();
  // 에러 메세지 저장
  const [error, setError] = useState();

  // Geolocation의 `getCurrentPosition` 메소드에 대한 성공 callback 핸들러
  const handleSuccess = (pos) => {
    const { latitude, longitude } = pos.coords;

    setLocation({
      latitude,
      longitude,
    });
  };

  // Geolocation의 `getCurrentPosition` 메소드에 대한 실패 callback 핸들러
  const handleError = (error) => {
    setError(error.message);
  };

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

    // 사용된 브라우저에서 지리적 위치(Geolocation)가 정의되지 않은 경우 오류로 처리합니다.
    if (!geolocation) {
      setError("Geolocation is not supported.");
      return;
    }

    // Geolocation API 호출
    geolocation.getCurrentPosition(handleSuccess, handleError, options);
  }, [options]);

  return { location, error };
};

export default useCurrentLocation;

 

위 Hooks를 살펴보면 geoLocation API중 getCurrentPosition 메서드를 이용하고 있습니다.

 

성공시 현재 위도와 경도를 담아서 Hook의 첫번째 인자로 반환 해주고, 에러 발생시에 에러 메세지를 두번째 인자로 반환해줍니다.

 

실제 컴포넌트에서 사용할땐 다음과 같이 사용합니다.

 

import React, { useEffect, useMemo, useState } from 'react'
import useWatchLocation from '@utils/hooks/useCurrentLocation'

const geolocationOptions = {
  enableHighAccuracy: true,
  timeout: 1000 * 60 * 1, // 1 min (1000 ms * 60 sec * 1 minute = 60 000ms)
  maximumAge: 1000 * 3600 * 24, // 24 hour
}

const showLatLong = () => {
  const { location: currentLocation, error: currentError } = useCurrentLocation(geolocationOptions);
  useEffect(() => {
    console.log('showLatLong 컴포넌트 렌더링')
  }, [])
  
  return <div>{location.latitude, location.longitude}</div>
}
  • location : 현재 위도와 경도를 담은 Object 
  • error : 에러 출력시 메세지 

 

useWatchLocation Hook으로 반복적으로 내 위치 불러오기

import { useState, useEffect, useRef } from "react";

const useWatchLocation = (options = {}) => {
  // 내 위치 정보 저장
  const [location, setLocation] = useState();
  // 에러 메세지 저장
  const [error, setError] = useState();
  // watch 인스턴스를 취소할 수 있도록 Geolocation의 `watchPosition`에서 반환된 ID를 저장합니다.
  const locationWatchId = useRef(null);

  // Geolocation의 `watchPosition` 메소드에 대한 성공 callback 핸들러
  const handleSuccess = (pos) => {
    const { latitude, longitude } = pos.coords;

    setLocation({
      latitude,
      longitude,
    });
  };

  // Geolocation의 `watchPosition` 메소드에 대한 실패 callback 핸들러
  const handleError = (error) => {
    setError(error.message);
  };

  // 저장된 `watchPosition` ID를 기반으로 감시 인스턴스를 지웁니다.
  const cancelLocationWatch = () => {
    const { geolocation } = navigator;

    if (locationWatchId.current && geolocation) {
      geolocation.clearWatch(locationWatchId.current);
    }
  };

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

    // 사용된 브라우저에서 지리적 위치(Geolocation)가 정의되지 않은 경우 오류로 처리합니다.
    if (!geolocation) {
      setError("Geolocation is not supported.");
      return;
    }

    // Geolocation API로 위치 감시 시작
    locationWatchId.current = geolocation.watchPosition(handleSuccess, handleError, options);

    // React가 사용된 구성 요소를 마운트 해제할 때 위치 감시 인스턴스를 지웁니다.
    return cancelLocationWatch;
  }, [options]);

  return { location, cancelLocationWatch, error };
};

export default useWatchLocation;

위 Hooks를 살펴보면 geoLocation API중 watchPosition 메서드를 이용하고 있습니다.

watchPosition이 지정된 시간마다 현재 위도와 경도를 담아서 Hook의 첫번째 인자로 반환해주고, 위치 감시를 끌 수 있는 메서드를 두번째 인자로 반환합니다. 에러 발생시에 에러 메세지를 세번째 인자로 반환해줍니다.

실제 컴포넌트에서 사용할땐 다음과 같이 사용합니다.

 

import React, { useEffect, useMemo, useState } from 'react'
import useWatchLocation from '@utils/hooks/useCurrentLocation'

// 컴포넌트 안쪽에서 선언하면 에러 발생
const geolocationOptions = {
  enableHighAccuracy: true,
  timeout: 1000 * 60 * 1, // 1 min (1000 ms * 60 sec * 1 minute = 60 000ms)
  maximumAge: 1000 * 3600 * 24, // 24 hour
}

const showLatLong = () => {
  const { location, cancelLocationWatch, error } = useWatchLocation(geolocationOptions);
  useEffect(() => {
    if (!location) return;
    
    // 3초후에 watch 종료
    setTimeout(() => {
      cancelLocationWatch();
    }, 3000);
  }, [])
  
  return <div>{location.latitude, location.longitude}</div>
}
  • location : 현재 위도와 경도를 담은 Object 
  • cancelLocationWatch: 실시간 위치 추적 종료
  • error : 에러 출력시 메세지 

주의점

 

추가적으로 useWatchLocation을 사용할때 옵션을 함수 컴포넌트 안에서 선언하면 위치를 제대로 못알아오는 문제가 발생할 수 있습니다.  그 이유는 useWatchLocation hooks에서 useEffect가 options가 바뀔때마다 재실행 되기 때문에 예상치 못한 문제가 발생할 수 있습니다. 

 

 

결론

지금까지 Hooks를 통해 geoLocation을 사용하는 방법을 알아봤습니다.

 

이번에는 좋은 외국 개발자분께서 만들어 놓은 Geolocation Hooks를 리뷰하는 방법으로 글을 작성하였는데요, 이렇게 누군가가 잘 만들어진 모듈을 가져다 쓸때는 감사한 마음으로 star를 눌러주세요 :) 또 작성자가 어떤 의도로 코드를 짰는지 한번쯤은 파악해보고 사용하는것도 꼭 필요한것 같습니다.

 

추가적으로 질문이 있으시면 언제든지 댓글이나 메일로 알려주시면 확인시에 바로 답변 드리겠습니다.

 

 

 

반응형