반응형
오류 내역
페이지가 로드될 때 카카오맵의 마커가 바로 생성되지 않고 어떤 추가 요청을 해야 나머지 마커를 불러오는 상황이 발생했다.
기존 코드 전체 보기
더보기
import React, { useState, useEffect } from 'react';
import { Map, MapMarker, CustomOverlayMap } from 'react-kakao-maps-sdk';
import { styled } from 'styled-components';
import { BiChevronRight } from 'react-icons/bi';
import { useNavigate } from 'react-router-dom';
// window.kakao 객체를 가져옴
const { kakao } = window;
const KakaoMap = ({ coords, storelist }) => {
const [markers, setMarkers] = useState([]);
// * 상세 페이지로 이동
const navigate = useNavigate();
const onOverlayClickHandler = (storeId) => navigate(`/StoreDetail/${storeId}`);
// * 주소-좌표 변환 객체를 생성
const geocoder = new kakao.maps.services.Geocoder();
// * storelist 주소를 지도에 마킹할 수 있도록 x, y값 변환
useEffect(() => {
const addMarkers = [];
storelist.forEach((item) => {
geocoder.addressSearch(item.address, (result, status) => {
if (status === kakao.maps.services.Status.OK && result[0]) {
addMarkers.push({
position: {
lat: result[0].address.y,
lng: result[0].address.x,
},
content: item.store,
id: item.store_id,
isOverlayVisible: false,
});
}
setMarkers(addMarkers);
});
});
}, [storelist]);
// * 업장 아이콘 클릭 시 overlay visible true/false
const onMarkerClickHandler = (markerId) => {
setMarkers((prevMarkers) =>
prevMarkers.map((marker) =>
marker.id === markerId ? { ...marker, isOverlayVisible: !marker.isOverlayVisible } : marker,
),
);
};
return (
<MapSection>
{/* 지도를 표시할 Container */}
<Map
center={{
lat: coords.lat,
lng: coords.lon,
}}
style={{
width: '100%',
height: '94%',
}}
level={5}
>
{markers &&
markers.map((marker) => (
<React.Fragment key={`marker_${marker.id}`}>
<MapMarker
position={marker.position}
image={{
src: 'https://cdn-icons-png.flaticon.com/512/2722/2722538.png',
size: {
width: 24,
height: 35,
},
options: {
offset: {
x: 15,
y: -7,
},
},
}}
onClick={() => onMarkerClickHandler(marker.id)}
/>
{marker.isOverlayVisible && (
<CustomOverlayMap
value={marker.isOverlayVisible}
position={marker.position}
yAnchor={1}
onClick={() => onMarkerClickHandler(marker.id)}
>
<OverlayDiv onClick={() => onOverlayClickHandler(marker.id)}>
{marker.content}
<BiChevronRight />
</OverlayDiv>
</CustomOverlayMap>
)}
</React.Fragment>
))}
</Map>
</MapSection>
);
};
export default KakaoMap;
오류가 발생한 원인
geocoder.addressSearch가 비동기도 동작하기 때문에 마커를 추가하는 반복문이 비동기적으로 실행되기 때문이었다!
오류 해결 방법
모든 주소의 좌표 변환 작업이 완료된 후 마커를 한꺼번에 추가할 수 있도록 하고, 이를 위해 비동기 작업들을 Promise와 Promise.all을 사용해 처리했다.
// * 주소-좌표 변환 객체를 생성
const geocoder = new kakao.maps.services.Geocoder();
// * storelist 주소를 지도에 마킹할 수 있도록 x, y값 변환
useEffect(() => {
// async 함수를 정의해 storelist에 있는 각 항목의 주소를 변환해 마커 데이터를 가져온다.
const fetchMarkerData = async () => {
// 마커 데이터를 저장하기 위한 빈 배열 변수
const addMarkers = [];
// 해당 배열은 변환된 각 주소에 대한 Promise 객체들을 저장한다.
const markerPromises = storelist.map((item) => {
// 주소 변환 작업에 대해 새로운 Promise 객체들을 생성한다.
// 이 Promise 객체는 addressSearch 메서드를 호출해 주소를 변환하고,
// 변환된 결과를 처리하는 비동기 작업을 수행한다.
return new Promise((resolve) => {
geocoder.addressSearch(item.address, (result, status) => {
if (status === kakao.maps.services.Status.OK && result[0]) {
addMarkers.push({
position: {
lat: result[0].address.y,
lng: result[0].address.x,
},
content: item.store,
id: item.store_id,
isOverlayVisible: false,
});
}
// 주소 변환 작업이 완료되면 Promise 객체를 reslove하여 완료됐음을 알린다.
resolve();
});
});
});
// Promise.all 메서드를 사용해 markerPromises 배열 안의
// 모든 Promise 객체들이 완료될 때까지 대기한다.
await Promise.all(markerPromises);
setMarkers(addMarkers);
};
fetchMarkerData();
}, [storelist]);
[해당 코드 전체 보기]
https://github.com/dawhisky/dawhisky-FE/blob/develop/src/pages/KakaoMap.jsx
반응형
'Front-End > React' 카테고리의 다른 글
[React] 카카오맵(2) 지도 이동 시 지도에 출력되는 위치 감지하기 (0) | 2023.06.06 |
---|---|
[React] React-router-dom을 이용한 Private Route 설정 시 인증/인가 처리 오류 (0) | 2023.06.03 |
[React] 카카오맵(1) 지도 내장 검색 기능 사용해 리스트 출력하기 (0) | 2023.06.01 |
[React] 디바운싱을 이용한 추천 검색어, 인기 검색어, 키워드 검색 기능 구현하기 (0) | 2023.05.31 |
[React] 리액트에서 Styled Components Global Style, Theme 설정하기 (0) | 2023.05.30 |