이전에 임의로 location을 설정했다면 이번에는 처음 페이지 접속/실행 시 현재 위치를 기준으로 지도를 렌더링하는 훅을 구현해 보자.
useGeolocation
훅 작성하기useGeolocation.ts
라는 파일을 생성 한다.
import { useState, useEffect } from 'react';
import { Latlng } from '../shared/types/map';
const useGeolocation = () => {
const [location, setLocation] = useState<Latlng | null>(null); // 현재 위치를 저장할 상태
return { location };
};
export default useGeolocation;
우선, useState
를 사용하여 현재 위치 정보를 저장할 상태를 초기화한 다음 상태의 초기값은 null로 설정한다.
여기서 Latlng은 위도(latitude)와 경도(longitude)를 미리 설정한 타입이다.
export interface Latlng {
latitude: number;
longitude: number;
}
컴포넌트가 처음 렌더링될 때 위치 정보를 요청해야 하므로, useEffect를 사용하여 위치 정보 요청 로직을 실행한다.
import { useState, useEffect } from 'react';
import { Latlng } from '../shared/types/map';
const useGeolocation = () => {
const [location, setLocation] = useState<Latlng | null>(null); // 현재 위치를 저장할 상태
useEffect(() => {
navigator.geolocation.getCurrentPosition(successHandler, errorHandler); // 성공시 successHandler, 실패시 errorHandler 함수가 실행된다.
}, []);
const successHandler = () => {};
const errorHandler = () => {};
return { location };
};
export default useGeolocation;
컴포넌트가 마운트될 때 usenavigator.geolocation.getCurrentPosition
메서드를 통해 브라우저의 Geolocation API를 사용하여 현재 위치를 가져올 수 있으며, 메소드는 순서대로 성공, 실패 시의 콜백 함수 2개를 인자로 받는다.
import { useState, useEffect } from 'react';
import { Latlng } from '../shared/types/map';
const useGeolocation = () => {
const [location, setLocation] = useState<Latlng | null>(null); // 현재 위치를 저장할 상태
useEffect(() => {
navigator.geolocation.getCurrentPosition(successHandler, errorHandler); // 성공시 successHandler, 실패시 errorHandler 함수가 실행된다.
}, []);
const successHandler = (response: {
coords: { latitude: number; longitude: number };
}) => {
const { latitude, longitude } = response.coords;
setLocation({ latitude, longitude });
};
const errorHandler = (error: GeolocationPositionError) => {
console.log(error);
};
return { location };
};
export default useGeolocation;
위치 정보 요청이 성공했을 때 호출되는 successHandler
함수는 response
객체를 인자로 받는다.
response.coords
는 Geolocation API가 반환하는 객체로, 여기서 latitude
와 longitude
를 추출해 setLocation
을 통해 상태를 업데이트한다.
위치 정보 요청이 실패했을 때 호출되는 errorHandler
함수는 GeolocationPositionError
타입의 error 객체를 인자로 받는다.
이전 2탄 지도 띄우기 포스트 글 작성 시 Map 객체 생성 시 임의의 위치값을 넣었었는데,
이번에는 useGeoLocation을 사용해 현재 위치 값을 넣어 Map 객체를 생성해 보자.
import useGeolocation from '@/app/_hooks/useGeolocation';
//...
const MapProvider: React.FC<MapProps> = ({ children }) => {
const { location } = useGeolocation(); // 현재 위치 값 불러오기
const mapRef = useRef<HTMLDivElement>(null);
const [map, setMap] = useState<kakao.maps.Map | null>(null);
const [markerClusterer, setMarkerClusterer] =
useState<kakao.maps.MarkerClusterer | null>(null);
const [overlays, setOverlays] = useState<kakao.maps.CustomOverlay[]>([]);
const [prevKeyword, setPrevKeyword] = useState<string[]>([]);
const [places, setPlaces] = useState<IPlace[]>([]);
const [prevLocation, setPrevLocation] = useState<kakao.maps.LatLng | null>(
null,
);
const [currLocation, setCurrLocation] = useState<kakao.maps.LatLng | null>(
null,
);
useEffect(() => {
const { kakao } = window;
kakao?.maps.load(() => {
const mapElement = mapRef.current;
// 컴포넌트 mount 후 DOM 요소에 접근
if (mapElement) {
const options = {
center: new kakao.maps.LatLng(
location?.latitude as number,
location?.longitude as number, // 현재 경도, 위도 적용
),
level: 3,
smooth: true,
tileAnimation: false,
};
// 지도 생성
const kakaoMap = new kakao.maps.Map(mapElement, options);
// 현재 중심좌표 값 갱신
kakao.maps.event.addListener(kakaoMap, 'dragend', function () {
const latlng = kakaoMap.getCenter();
setCurrLocation(latlng);
});
setMap(kakaoMap);
}
});
}, [location?.latitude, location?.longitude]);