1. 설치
npm install react-kakao-maps-sdk
2. <script> 태그 추가
이 라이브러리를 사용하기 위해서는 필수적으로 Kakao Maps API를 불러와야 한다.
API 키 발급받는 법
<script type="text/javascript" src="//dapi.kakao.com/v2/maps/sdk.js?appkey=발급받은 APP KEY&libraries=services,clusterer" ></script>
KakaoMap.jsx
import React, { useState, useEffect } from "react"; import { Map, MapMarker } from "react-kakao-maps-sdk"; const KakaoMap = ({ keyword, latitude, longitude }) => { const { kakao } = window; const [info, setInfo] = useState(); const [markers, setMarkers] = useState([]); const [map, setMap] = useState(); const [mapLength, setMapLength] = useState(1000); useEffect(() => { const overlayBox = document.querySelector(".overlaybox"); if (overlayBox) { const grandParent = overlayBox.parentElement.parentElement; if (grandParent) { setBorder(grandParent.style.border); // border 값을 업데이트합니다. grandParent.style.border = "0"; // border 값을 0으로 설정합니다. } } }, []); useEffect( () => { if (!map) return; if(mapLength===1000){ createMap(keyword); } if(mapLength===0){ createMap(keyword); // 예 let address = "충청북도 청주시 상당구 미원면"; //만약에 검색된 스터디카페 값이 없다면 충청북도 청주시 까지로 해서 검색 let parts = keyword.split(" "); let result = parts[0] + " " + parts[1]; console.log(result); // 출력: "충청북도 청주시" createMap( result); } }, [map,mapLength]); async function createMap(keyword){ const ps = new kakao.maps.services.Places(); ps.keywordSearch(`${keyword} 스터디카페`, async (data, status, _pagination) => { setMapLength(data.length); if (status === kakao.maps.services.Status.OK) { // 검색된 장소 위치를 기준으로 지도 범위를 재설정하기위해 // LatLngBounds 객체에 좌표를 추가합니다 const bounds = new kakao.maps.LatLngBounds(); let markers = []; for (var i = 0; i < data.length; i++) { // @ts-ignore markers.push({ position: { lat: data[i].y, lng: data[i].x, }, content: data[i].place_name, }); // @ts-ignore bounds.extend(new kakao.maps.LatLng(data[i].y, data[i].x)); } setMarkers(markers); // 검색된 장소 위치를 기준으로 지도 범위를 재설정합니다 map.setBounds(bounds); //보더값 제거 배경색 투명 const overlayBox = document.querySelector(".overlaybox"); if (overlayBox) { const grandParent = overlayBox.parentElement.parentElement; if (grandParent) { setBorder(grandParent.style.border); // border 값을 업데이트합니다. setBackgroundColor(grandParent.style.background); grandParent.style.border = "0"; // border 값을 0으로 설정합니다. grandParent.style.background = "rgba(255,255,255,0)"; } } } }); } return ( <div> <Map center={{ lat: latitude, lng: longitude }} style={{ width: "100%", height: "700px", borderRadius: "20px", }} level={3} onCreate={setMap} > {/* //지도에 보여줄 위치 지정 (위도,경도) */} {markers.map((marker) => ( <MapMarker style={{ border: "tranparent" }} //position={{ lat: latitude, lng: longitude }} key={`marker-${marker.content}-${marker.position.lat},${marker.position.lng}`} position={marker.position} onClick={() => setInfo(marker)} image={{ src: "https://cdn-icons-png.flaticon.com/512/5737/5737612.png", size: { width: 50, height: 50 } }} > {info && info.content === marker.content && ( <> <div style={{ color: "#000", fontSize: "16px", fontWeight: "600", border: "2px solid #e30d7c", borderRadius: "5px", padding: "5px", backgroundColor: "#ffffff", boxShadow: "0 0 10px rgba(0, 0, 0, 0.1)", width: "300px", textAlign: "center", }} > ☕???? {marker.content} </div> </> )} </MapMarker> ))} </Map> </div> //핀에 적힐 이름 (위치 이름) ); }; export default KakaoMap;
StudyCafeFinder
import Header from "../../components/Header"; import { useLoaderData } from "react-router-dom"; import { API_BASE_URL } from "../../api-config"; import { getAuthToken, getUser } from "../../util/auth"; import KakaoMap from "../../components/KakaoMap"; import UserTable from "../../components/UserTable"; const { kakao } = window; const StudyCafeFinder = () => { const { findCafeInfo } = useLoaderData(); return ( <> <div> <Header /> <main className="container mt-5"> {findCafeInfo && findCafeInfo.users && ( <UserTable users={findCafeInfo.users} /> )} <KakaoMap keyword={findCafeInfo.address} latitude={findCafeInfo.lat} longitude={findCafeInfo.lng} /> </main> </div> </> ); }; export default StudyCafeFinder; // 로더 함수 export async function loader({ request, params }) { const token = getAuthToken(); const user = getUser(); const response = await fetch(`${API_BASE_URL}/users/studyCafeFinder`, { method: "POST", body: JSON.stringify(user), headers: { "Content-Type": "application/json", Authorization: "Bearer " + token, }, }); if (!response.ok) { return json({ message: "데이터를 가져올 수 없습니다." }, { status: 500 }); } else { //좌표 let findCafeInfo = ""; const searchOptionArray = []; let users = ""; let getAddress = ""; const resData = await response.json(); users = resData.result; const addresses = await users.map((user) => { return user.address; }); //샘플 예 // const addresses = [ // "서울 송파구 동남로 99", // "서울 강남구 테헤란로 212", // "대구 수성구 동대구로 441", // ]; const newAddresses = addresses.map((address) => { const parts = address.split(" "); parts.pop(); // 마지막 요소(번지수)를 제거합니다. return parts.join(" "); // 주소를 다시 합칩니다. }); try { //1.주소로 좌표 구하기 await latAndLong(newAddresses, searchOptionArray); //2.중간좌표 구하기 findCafeInfo = await centerPosition(searchOptionArray); //3.중간좌표로 주소 구하기 getAddress = await getAddressFn(findCafeInfo) .then((res) => res) .catch((err) => console.error(err)); } catch (error) { console.log("error :", error); } findCafeInfo.users = users; findCafeInfo.address = getAddress; return { findCafeInfo: findCafeInfo }; } } //1.주소로 좌표 구하기 async function latAndLong(addresses, searchOptionArray) { const geocoder = new kakao.maps.services.Geocoder(); const promises = addresses.map( (address) => new Promise((resolve, reject) => { geocoder.addressSearch(address, function (result, status) { if (status === kakao.maps.services.Status.OK) { const coords = new kakao.maps.LatLng(result[0].y, result[0].x); const searchOption = { location: coords, radius: 2000, sort: kakao.maps.services.SortBy.DISTANCE, }; resolve(coords); } else { reject(new Error("Failed to get coordinates")); } }); }) ); await Promise.all(promises) .then((coordsArray) => { searchOptionArray.push(...coordsArray); }) .catch((error) => console.error(error)); return searchOptionArray; } //2. 중간좌표 구하기 async function centerPosition(locations) { //ex) const locations = [ // { La: 127.047486752713, Ma: 37.504059366187 }, // { La: 126.976425200039, Ma: 37.5626231544518 }, // { La: 126.978989954189, Ma: 37.5735042429813 } // ]; let sumLat = 0; let sumLng = 0; locations.forEach((location) => { sumLat += location.Ma; sumLng += location.La; }); const avgLat = sumLat / locations.length; const avgLng = sumLng / locations.length; return { lat: avgLat, lng: avgLng }; } //3.좌표를 이용해서 주소값 가져오기 async function getAddressFn({ lat, lng }) { const geocoder = new window.kakao.maps.services.Geocoder(); const res = await new Promise((resolve, reject) => { geocoder.coord2RegionCode(lng, lat, (result, status) => { if (status === window.kakao.maps.services.Status.OK) { for (let i = 0; i < result.length; i++) { if (result[i].region_type === "H") { resolve(result[i].address_name); } } } else { reject(new Error("주소를 찾을 수 없습니다.")); } }); }); return res; }
댓글 ( 0)
댓글 남기기