Next.js에서 네이버 지도 API 사용하기

김하은·2025년 1월 27일
0

Next.js

목록 보기
1/2
post-thumbnail

Next.js에서 Script 컴포넌트를 이용해 네이버 지도 API를 동적으로 로드하고, 네이버 지도를 생성하는 방법을 정리해보았습니다.

네이버 지도 구현의 주요 3단계

  1. 외부 스크립트 동적으로 로드
    • 네이버 지도 API 스크립트를 동적으로 로드
  2. 네이버 지도를 삽입할 DOM 설정
    • 지도 렌더링을 위한 DOM 요소를 useRef로 관리
  3. 설정한 DOM에 네이버 지도 생성
    • 네이버 지도 API를 사용해 지도를 초기화 및 렌더링

각 단계에서 만난 의문점(❓)이슈(🚧)를 함께 기록하면서 문제를 어떻게 해결했는지도 함께 작성해 보았습니다.


1. Script 컴포넌트: 네이버 지도 API 동적 로드

Next.js에서 네이버 지도 API를 동적으로 로드하려면 Script 컴포넌트를 사용해야 합니다. 아래는 네이버 지도 API를 strategy="afterInteractive" 옵션과 함께 로드하는 방법입니다.

import Script from "next/script";

export default function Dashboard() {
  return (
    <>
      <Script
        src="https://example.com/script.js"
        strategy="afterInteractive"
      />
    </>
  );
}
  • strategy 옵션:
    • beforeInteractive: 초기 렌더링 전에 스크립트를 로드. 모든 페이지에서 전역적으로 적용할 경우에 사용
    • afterInteractive: 렌더링이 끝난 후 스크립트를 로드. 특정 페이지에서만 필요한 비필수 스크립트에 적합

❓ 스크립트를 동적 로드해야 하는 이유

  • 성능 최적화: 네이버 지도 API는 약 88.3KB의 스크립트로, 크기가 크진 않지만, 지도 기능이 필요 없는 페이지에서는 로드하지 않음으로써 네트워크 요청과 초기 로딩 시간을 줄일 수 있음
  • 리소스 관리: 지도 API 스크립트는 모든 페이지에서 필요하지 않기 때문에, 필요한 페이지에서만 동적으로 로드하는 것이 성능 관점에서 더 효율적임

2. useRef로 DOM 설정: 네이버 지도 렌더링 준비

네이버 지도를 렌더링하려면 지도를 삽입할 DOM 요소를 지정해야 합니다. 여기서는 React의 useRef를 사용해 DOM 요소를 참조합니다.

export default function NaverMap({ coords }: { coords: TCoords }) {
  const mapRef = useRef<HTMLDivElement | null>(null);

  return (
    <>
      <Script
        src="https://example.com/script.js"
        strategy="afterInteractive"
      />
      <div className="naver-map" ref={mapRef} />
    </>
  );
}

❓ 왜 useRef를 사용하는가?

id를 사용할 수도 있지만, React에서는 useRef가 더 안전하고 권장됩니다.

특성useRefid
React와 동기화React 렌더링 모델과 자연스럽게 동기화됨.DOM 렌더링 여부와 React 상태가 불일치할 가능성.
조건부 렌더링렌더링 후 자동으로 ref에 설정.렌더링 조건에 따라 DOM 요소를 찾지 못할 수 있음.
안전성컴포넌트 내부적으로 안전하게 관리.전역적으로 id 중복 가능성으로 예기치 않은 문제 발생.

3. initializeMap 함수: 네이버 지도 생성

initializeMap 함수는 설정한 DOM(mapRef.current)에 네이버 지도를 생성하고, 마커와 이벤트 리스너를 추가합니다.

export const initializeMap = (
  mapRef: MutableRefObject<HTMLDivElement | null>,
  coords: TCoords,
) => {
  const { latitude, longitude } = coords;

  if (mapRef.current && window.naver) {
    // 지도 옵션 설정
    const mapOptions = {
      center: new window.naver.maps.LatLng(latitude, longitude),
      zoom: 15,
      minZoom: 12,
    };

    // 네이버 지도 생성
    const map = new window.naver.maps.Map(mapRef.current, mapOptions);

    // 마커 설정
    const marker = new window.naver.maps.Marker({
      position: new window.naver.maps.LatLng(latitude, longitude),
      map: map,
      icon: {
        url: "/images/lawyers/mapMarker.svg",
        size: new naver.maps.Size(24, 30),
      },
    });

    // 이벤트 리스너 설정
    window.naver.maps.Event.addListener(marker, "click", () => {
      const redirectUrl = generateNaverMapLink(coords);
      window.open(redirectUrl, "_blank");
    });
  } else {
    console.error(NAVER_MAP_ERRORS.containerNotFound);
  }
};

4. Script의 onLoad와 useEffect: 동작 문제 해결

🚧 문제 1: window.naver가 정의되지 않음

  • initializeMap이 실행될 때 window.naver가 아직 로드되지 않아서 에러 발생

해결책: Script의 onLoad 사용

onLoad를 활용하여 스크립트가 로드된 이후에만 initializeMap을 호출

<Script
  src="https://example.com/script.js"
  strategy="afterInteractive"
  onLoad={() => {
    if (mapRef.current) {
      initializeMap(mapRef, coords);
    }
  }}
/>

🚧 문제 2: 탭 전환 후 지도가 렌더링되지 않음

  • onLoad는 스크립트 로드 시 한 번만 실행되므로, 탭 전환 후 다시 렌더링될 때 initializeMap이 호출되지 않음

해결책: useEffect로 상태 변화 처리

useEffect를 사용해 컴포넌트가 다시 렌더링될 때도 initializeMap이 호출되도록 수정

useEffect(() => {
  if (window.naver && mapRef.current) {
    initializeMap(mapRef, coords);
  }
}, [coords]);

최종 코드

아래는 개선된 최종 코드입니다.

export default function NaverMap({ coords }: { coords: TCoords }) {
  const mapRef = useRef<HTMLDivElement | null>(null);

  useEffect(() => {
    if (window.naver && mapRef.current) {
      initializeMap(mapRef, coords);
    }
  }, [coords]);

  return (
    <>
      <Script
        type="text/javascript"
        src={NAVER_MAP_SCRIPT}
        strategy="afterInteractive"
        onLoad={() => {
          if (mapRef.current) {
            initializeMap(mapRef, coords);
          } else {
            console.error(NAVER_MAP_ERRORS.apiNotLoaded);
          }
        }}
        onError={() => {
          console.error(NAVER_MAP_ERRORS.scriptLoadFailed);
        }}
      />
      <div className={cx("naver-map")} ref={mapRef} />
    </>
  );
}

결과

  1. 스크립트 동적 로드

    성능 최적화 및 필요 페이지에서만 로드

  2. DOM 설정 및 지도 렌더링

    스크립트 로드 후 네이버 지도 API 정상 작동

    탭 전환 후에도 안정적으로 지도 생성

profile
아이디어와 구현을 좋아합니다!

0개의 댓글

관련 채용 정보