일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
- url
- bootstrap
- nosql
- db
- 배포
- Github Pages
- W
- github
- this
- REACT
- firestoredatabase
- IntersectionObserver
- data
- http
- til
- Database
- web
- HTML
- Fetch
- CSS
- useEffect
- SQL
- JavaScript
- Cloud
- jQuery
- TMDB
- API
- Boostrap
- Protocol
- supabase
- Today
- Total
072DATA
친환경 스토어 지도 개발 로그 2편 ( 카카오맵 불러오기, 마커와 인포 윈도우 생성 ) 본문
지난 시간에는 서울 맵의 친환경 스토어 데이터를 분석하고
supabase에 저장하는 과정을 기록했는데욥
이번 글에서는 실제로 카카오맵을 불러오는 과정을 기록하겠습니다.
먼저 카카오맵 API 문서에 나와있는 시작하기를 따라하면서
개발자 등록 및 API 키를 발급받아야 합니다.
그리고 타입 지원이나 지도를 더 원할하게 사용하기 위해서 카카오맵 SDK 라이브러리를 사용합니다
npm install react-kakao-maps-sdk
혹은
yarn add react-kakao-maps-sdk
카카오맵 API 가이드
https://apis.map.kakao.com/web/guide/
카카오맵 SDK 가이드
https://react-kakao-maps-sdk.jaeseokim.dev/docs/intro
카카오 지도 불러오기
const KAKAO_SDK_URL = `//dapi.kakao.com/v2/maps/sdk.js?appkey=${process.env.NEXT_PUBLIC_KAKAO_APP_JS_KEY}&autoload=false`;
const KakaoMap = () => {
return (
<>
<Script src={KAKAO_SDK_URL} strategy="beforeInteractive" />
<div className="w-full h-screen"> {/* 지도 컨테이너 크기 설정 */}
<Map
center={{
lat: 37.566826, // 서울시청 위도
lng: 126.978656, // 서울시청 경도
}}
style={{
width: "100%",
height: "100%",
}}
level={8} // 지도 확대 레벨
draggable={true} // 드래그 가능
zoomable={true} // 줌 가능
/>
</div>
</>
);
};
카카오 맵 API 키를 .env.local에 환경변수로 저장하고
해당 URL을 Scirpt의 src에 삽입합니다
또 지도의 기본 위치를 서울 시청을 중심으로 잡았고
드래그와 줌 기능 지도의 확대 레벨을 8로 설정하였습니다
지도 로딩 개선
지도 페이지에서 지도가 원할하게 불러와지지 않고
새로고침을 통해서만 로드되는 버그가 생겼는데
이를 해결하기 위해서 Script 태그를 사용하지 않고
useEffect와 useState를 사용하여 카카오 맵 API의
스크립트를 비동기적으로 불러올 수 있도록 개선했습니다.
const [isMapLoaded, setIsMapLoaded] = useState<boolean>(false);
useEffect(() => {
const script = document.createElement("script");
script.src = `//dapi.kakao.com/v2/maps/sdk.js?appkey=${process.env.NEXT_PUBLIC_KAKAO_APP_JS_KEY}&autoload=false`;
script.async = true;
script.onload = () => {
window.kakao.maps.load(() => {
setIsMapLoaded(true);
});
};
document.head.appendChild(script);
return () => {
document.head.removeChild(script);
};
}, []);
- useState<boolean>(false): isMapLoaded라는 상태를 생성해서 맵이 로드되었는지 여부를 나타냅니다
- useEffect:useEffect 내부에서 스크립트를 동적으로 생성하여 문서의 <head>에 추가하는 방식으로 카카오 맵 API를 불러옵니다
- 스크립트 로드:
- const script = document.createElement("script");로 <script> 태그를 동적으로 생성합니다
- script.src 로 카카오 맵 SDK의 URL을 설정합니다 환경 변수에 저장된 API키를 사용합니다
- script.async = true로 비동기 로드를 설정하여 페이지 로드 성능에 영향을 최소화합니다.
- script.onload: 스크립트 로드가 완료되면 실행되는 콜백 함수입니다. window.kakao.maps.load() 함수를 호출하여 맵 API 로드가 완료되면 콜백이 실행되고, 그 안에서 setIsMapLoaded(true)를 호출하여 isMapLoaded 상태를 true로 설정합니다.
- 정리 함수: return문 안에서 정리 함수로 document.head.removeChild(script);를 호출하여 컴포넌트가 언마운트될 때 스크립트를 <head>에서 제거합니다.
이렇게 해서 페이지 첫 로드시에 지도가 바로 표시되고 isMapLoaded 상태를 사용해서
지도 로딩 기능도 추가할 수 있을듯 합니다!
결과물
마커와 인포윈도우 구현
마커아 인포윈도우를 구현하기 전 데이터가 존재해야 합니다
export const useStoreList = () => {
return useQuery({
queryKey: ["ecoStores"],
queryFn: getStoreList,
staleTime: 5 * 60 * 1000,
retry: 3
});
};
Tanstack Query를 사용해서 데이터를 요청하였습니다
getStoreList 함수는 단순히 데이터 요청 함수입니다
const { data: storeList, isLoading, error } = useStoreList();
<KakaoMap
storeList={storeList || []}
/>
그리고 요청 받은 데이터를 KakaoMap 컴포넌트에 props로 전달합니다ㅣ
이제 마커와 인포 윈도우를 구현하겠습니다
마커 구현
react-kakao-maps-sdk의 MapMarker 컴포넌트를 사용하여 구현했으며
지도 레벨(zoom)이 5 이하일 때만 마커가 표시되도록 설정했습니다
그리고 마커 클릭 시 해당 스토어 정보를 표시하는 이벤트 핸들러 구현했습니닷
{level <= 5 && storeList?.map((store) => (
<MapMarker
key={store.store_id}
position={{ lat: store.lat, lng: store.lon }}
onClick={() => onClick(store)}
>
{/* 인포윈도우 내용 */}
</MapMarker>
))}
인포윈도우 구현
MapMarker 컴포넌트의 자식 요소로 인포윈도우 내용을 구현하고
선택된 스토어일 때만 인포윈도우가 표시되도록 조건부 렌더링을 넣었으며
스토어 이름, 주소, 운영시간, 연락처 등 상세 정보를 표시했습니다
{selectedStoreId === store.store_id && (
<div className="p-2 w-[280px]">
<div className="mb-2 pb-2 border-b border-gray-100">
<h3 className="font-bold text-gray-800">{store.store_name}</h3>
</div>
<div className="text-sm space-y-1">
<div className="text-gray-600">{store.road_address}</div>
<div className="text-gray-500">{store.operating_hours}</div>
<div className="text-gray-500">{store.contact_number}</div>
</div>
</div>
)}
const [selectedStoreId, setSelectedStoreId] = useState<string | null>(null);
그리고 이 상태를 가지고 인포윈도우 내용을 구현하는 것 뿐만 아니라
지도를 이동시키거나 검색창에서 해당 카드에 대한 위치 이동 및 인포 윈도우 출력 등
다양한 기능을 구현이 가능합니다...!
결과물
마치며
여기까지 카카오맵을 실제로 불러오고 마커와 인포 윈도우를 출력해보았습니다!
다음으로 진행할 사항은 이전에 supabase에 삽입해둔 데이터를 기반으로
리스트 렌더링을 진행하고 해당 장소들의 위치에 따라 마커와 인포 윈도우를 등록,
리스트에 존재하는 카드나 마커 클릭시 지도가 이동하는 클릭 이벤트를 구현할 계획입니다
3편에서 뵙겠습니닷..
1편
https://0723-0725.tistory.com/107
'FrontEnd > Next.js' 카테고리의 다른 글
친환경 스토어 지도 개발 로그 3편 ( 리스트 렌더링,클릭 이벤트, 디바운싱 기법을 사용한 검색, 로딩처리 ) (4) | 2024.11.12 |
---|---|
친환경 스토어 지도 개발 로그 1편 ( 데이터 분석 및 삽입 ) (1) | 2024.11.09 |
react-hook-form으로 폼 유효성 검사 구현 (0) | 2024.11.04 |
다중으로 이미지 업로드 구현하기 ( supabase Storage ) (0) | 2024.10.29 |
OOTW 프로젝트 - 글 작성 구현하기 ( 이미지 업로드 ) (2) | 2024.10.18 |