카카오맵을 구현해보려고 하는데, 아래의 사진과 같은 에러가 뜨면서 렌더링이 되지 않았다!
콘솔에 찍힌 내용들을 차근 차근 읽어보고 검색해보아도, 별다른 해결책을 찾지 못했다.
코드는 아래와 같다.
import React, { useEffect, useState } from "react";
const KakaoMap = () => {
const { kakao } = window;
const [isLoaded, setIsLoaded] = useState(false);
useEffect(() => {
if (!kakao.maps) {
return;
}
// 카카오 지도 객체 생성 예제
const container = document.getElementById("map"); // 지도를 표시할 div
const options = {
center: new kakao.maps.LatLng(37.5665, 126.978), // 초기 위치
level: 3, // 초기 확대 레벨
};
const map = new kakao.maps.Map(container, options);
// // 지도에 마커 추가
const marker = new kakao.maps.Marker({
position: new kakao.maps.LatLng(37.5665, 126.978),
});
marker.setMap(map);
setIsLoaded(true);
}, [kakao.maps]);
return (
<div>
{isLoaded ? (
<div id="map" style={{ width: "100%", height: "400px" }}></div>
) : (
<p>Loading map...</p>
)}
</div>
);
};
export default KakaoMap;
여기서 문제점은 무엇일까요?
- 전역 객체인 kakao가 제대로 읽어들여지지 않았다.
- useEffect의 어떤 원리 때문에, 시간 차가 발생하여 kakao는 결국 읽어졌으나 kakao.maps가 state가 아니므로 리렌더링이 유발되지 않는다.
- useEffect의 어떤 원리 때문에, 렌더링 되고 난 후 useEffect의 콜백 함수 실행 과정에서 문제가 생겼다.
정답은?
.
.
.
.
.
.
.
.
.
.
.
3번!
사실 1,2,3번 모두 문제의 원인 후보에 들만한 사유들입니다.
따라서 전부 콘솔로그로 찍어보고, 주석화도 해보면서 디버깅을 해봤어요!
1. 전역 객체로 선언된 kakao의 경우 잘 읽혀지고 있었고(어느 시점에서든! → 사실 <script> 태그를 통해 <head>에 먼저 가져오므로 당연히 잘 읽혀집니다. 순서가 꼬이는 일은 없어요! - 스크립트가 실행이 안될 수도는 있어도..)
2. useEffect의 dependancy로 state와 같이 변하는 값이 아닌 전역 객체의 값을 넣어둔 것 또한 리렌더링을 발생시키지 않기에, 굉장히 이상한 코드인 것은 맞습니다.
그러나 3번이 원인인 것은..
return (
<div>
{isLoaded ? (
<div id="map" style={{ width: "100%", height: "400px" }}></div>
) : (
<p>Loading map...</p>
)}
</div>
);
};
바로 이 부분 때문입니다 ! isLoaded가 false이면 <p> 태그가 렌더링되는데 그렇게 된다면,
useEffect(() => {
if (!kakao.maps) {
return;
}
// 카카오 지도 객체 생성 예제
const container = document.getElementById("map"); // 지도를 표시할 div
const options = {
center: new kakao.maps.LatLng(37.5665, 126.978), // 초기 위치
level: 3, // 초기 확대 레벨
};
const map = new kakao.maps.Map(container, options);
// // 지도에 마커 추가
const marker = new kakao.maps.Marker({
position: new kakao.maps.LatLng(37.5665, 126.978),
});
marker.setMap(map);
setIsLoaded(true);
}, [kakao.maps]);
이 useEffect 함수의 콜백 함수 내에서
const container = document.getElementById("map"); // 지도를 표시할 div
const options = {
center: new kakao.maps.LatLng(37.5665, 126.978), // 초기 위치
level: 3, // 초기 확대 레벨
};
const map = new kakao.maps.Map(container, options);
여기! getElementById 해오는 부분이 null이 되어버리고, 그럼 kakao.maps.Map의 첫번째 인자로 null을 넘겨버리니까 타입 에러가 나면서 렌더링이 안되는겁니다! 이해 되셨나요?
원인을 찾았으니, 쓸데없는 로직들 제외하면서 코드를 더욱 깔끔하게 만들어봅시다 ~!
import React, { useEffect, useState } from "react";
const KakaoMap = () => {
const { kakao } = window;
const [isLoaded, setIsLoaded] = useState(false);
useEffect(() => {
setIsLoaded(true); //다음 번에는 바로 로딩이 되도록 해당 위치에 정의
if (!isLoaded) {
//이래야 getElementById가 정상적으로 작동함
return;
}
// 카카오 지도 객체 생성 예제
const container = document.getElementById("map"); // 지도를 표시할 div
const options = {
center: new kakao.maps.LatLng(37.5665, 126.978), // 초기 위치
level: 3, // 초기 확대 레벨
};
const map = new kakao.maps.Map(container, options);
// // 지도에 마커 추가
const marker = new kakao.maps.Marker({
position: new kakao.maps.LatLng(37.5665, 126.978),
});
marker.setMap(map);
}, [isLoaded]);
return (
<div>
{isLoaded ? (
<div id="map" style={{ width: "100%", height: "400px" }}></div>
) : (
<p>Loading map...</p>
)}
</div>
);
};
export default KakaoMap;
'Develop > Frontend' 카테고리의 다른 글
Web Socket을 도입하며 겪었던 트러블 슈팅들 (0) | 2024.12.31 |
---|---|
HTTP 그리고 Socket (Web Socket, 웹소켓) (2) | 2024.12.27 |
emotion에서 Theme 을 제대로 인식하지 못하는 에러 (+ 자동 완성도 불가능) (7) | 2024.11.10 |
React + Typescript 설치 시 생기는 에러 해결 (1) | 2024.11.10 |
Next.js 톺아보기 (3) | 2024.11.04 |