프로젝트를 진행 중 네이버지도 API를 사용하는 페이지를 담당하게 되었다.
외부 API를 사용하는 건 처음이라 문제점이 많을 거라고 생각은 했지만 생각보다 더 오랜 기간동안 붙잡고 있었다.
그 중에서도 지도를 사용하는 페이지를 초기 진입시 지도 랜더링이 되긴 하지만, 에러가 발생하는 문제로 꽤나 고생을 하고있었다.
초기 코드
지도
const testMap = () => {
let lat = 37.359531;
let lng = 127.1052133;
let map: naver.maps.Map;
useEffect(() => {
const location = new naver.maps.LatLng(lat, lng);
//지도 그리기
map = new naver.maps.Map('map', {
center: location,
zoomControl: true, // 줌 설정
zoom: 15,
zoomControlOptions: {
style: naver.maps.ZoomControlStyle.SMALL,
position: naver.maps.Position.TOP_RIGHT,
},
});
var marker = new naver.maps.Marker({
position: new naver.maps.LatLng(lat, lng),
map: map
});
myLocation(map);
}, [lat, lng]);
아래와 같이 RootLayout으로 스크립트를 빼놓고 페이지 진입시 useEffect를 통해 지도를 그린 후 마커를 찍는 방식이였다.
export default function RootLayout({
children,
}: Readonly<{
children: React.ReactNode;
}>) {
return (
<>
<Header />
<div>
<Script strategy='beforeInteractive' src="https://openapi.map.naver.com/openapi/v3/maps.js?ncpClientId=*********" />
{children}
</div>
</>
);
}
문제점1
하지만 스크립트의 beforeInteractive속성 때문에 지도가 렌더링이 끝나기 전에 네이버 지도를 우선 호출해버려서 에러가 발생하는 것이였다.
트러블 슈팅 1
그래서 afterinteractive로 바꿔준 뒤 스크립트를 지도컴포넌트로 옮기고, 지도가 랜더링이 끝난 후에 onLoad함수를 통해서 지도를 그려주도록 했다.
<Script
strategy="afterInteractive"
src="https://openapi.map.naver.com/openapi/v3/maps.js?ncpClientId=*******"
onLoad={initializeMap}
/>
문제점2
이렇게 수정을 하니 지도가 랜더링이 됐을 때 오류는 발생하지 않았지만, 백엔드와 axios로 통신하여 받아오는 데이터가
비동기로 받아오고 있었기 때문에, 데이터가 받아와지기 전에 스크립트가 실행되고, 지도를 그리는 함수가 onLoad를 통해 그려졌기 때문에 지도에는 여전히 데이터가 불러와지지 않아서 마커가 찍히지 않고 있었다.
그래서 나는 예외처리를 해주고 페이지 새로고침을 하면 비동기로 받아오던 데이터가 전부 불러와진 상태였기 때문에, 리랜더링이 되면서 데이터를 온전히 받아와 마커를 정상적으로 찍을 수 있다고 생각했다.
트러블 슈팅2
try {
console.log(storeInfo);
//맛집 리스트 지도 설정
if (storeInfo?.length > 1) {
map = new naver.maps.Map("map", {
center: new naver.maps.LatLng(
myLatLng?.latitude,
myLatLng?.longitude
),
zoomControl: true,
zoom: 14,
minZoom: 6,
zoomControlOptions: {
style: naver.maps.ZoomControlStyle.medium,
position: naver.maps.Position.TOP_RIGHT,
},
});
//맛집 상세 지도 설정
} else if (storeInfo?.length == 1) {
map = new naver.maps.Map("map", {
center: new naver.maps.LatLng(
storeInfo[0]?.latitude,
storeInfo[0]?.longitude
),
zoomontrol: true,
zoom: 15,
minZoom: 6,
zoomControlOptions: {
style: naver.maps.ZoomControlStyle.LARGE,
position: naver.maps.Position.TOP_RIGHT,
},
});
}
} catch (err) {
console.error(err);
router.refresh();
}
지도를 랜더링 해주는 코드를 try catch문으로 감싸서 api로 받아오는 정보인 storeInfo의 길이로 판단해, 비동기로 받아오는 데이터가 아직 넘어오지 않았다면, catch문을 통해 router.refresh()를 시켜줌으로써 페이지 새로고침을 통해 지도를 리랜더링 시켜주도록 했다.
useEffect(() => {
initializeMap();
}, [storeInfo]);
그리고 useEffect안에 작성했던 지도를 랜더링하는 코드를 분리하고, 그 함수만 작성해서 storeInfo(가게정보)가 바뀔 때 마다 리랜더링 시켜주는 방식으로 변경했다.
마지막으로..
사실 refresh를 통해서 강제(?)로 새로고침을 해서 불러오는 방법이 최선은 아닌 거 같다. 예외처리가 되지 않아 에러가 발생하는 부분은 잘 캐치를 한 거 같은데, 결과적으로 데이터를 불러오는 과정은 만족스럽지는 못하다.. 더 최선의 방법을 찾고 꼭 수정 해야겠다.