인프런 커뮤니티 질문&답변

bj2525님의 프로필 이미지
bj2525

작성한 질문수

Next.js 시작하기(feat. 지도 서비스 개발)

Marker UI 그리기

상태관리 질문 있습니다!

해결된 질문

작성

·

369

1

안녕하세요 용주님

swr 대신에 React-query랑 Recoil로 상태관리를 하고 있는데, map에 대한 data를 setMapInfo에 저장하고 있고, Markers에서 mapInfo에 대한 값을 useRecoilValue로 가져오고 있는 상황입니다.

 

const [mapInfo, setMapInfo] = useRecoilState(mapState)

  const initializeMap = () => {
    const mapOptions = {
      center: new window.naver.maps.LatLng(...initialCenter),
      zoom: initialZoom,
      minZoom: 9,
      scaleContorl: false,
      mapDataControl: false,
      logoControlOptions: {
        position: naver.maps.Position.BOTTOM_LEFT,
      },
    }

    let map = new window.naver.maps.Map(mapId, mapOptions)
    mapRef.current = map


    setMapInfo(map)
  }

 

그런데 계속 아래와 같이 Type error가 발생하고 있는 상황입니다. 어떤 문제 때문에 발생하는지 알 수 있을까요? 수업과 무관한 질문이여서 죄송합니다! ㅜ

참고로 @types/navermaps : 3.6.5 버전입니다.

 

스크린샷 2023-08-30 오전 12.21.26.png

답변 1

0

박용주님의 프로필 이미지
박용주
지식공유자

안녕하세요 질문 감사합니다.

이 질문(https://www.inflearn.com/questions/950781/kakaomap-%EC%9C%BC%EB%A1%9C-%EA%B5%AC%ED%98%84-%ED%95%98%EA%B3%A0-%EC%8B%B6%EC%9D%80%EB%8D%B0%EC%9A%94)과 비슷한 상황인 것 같긴 한데, 코드를 전체적으로 어떻게 수정하신지 정확히 파악하기 힘든 것 같습니다.

Marker 컴포넌트가 mount되는 시점이 window.naver가 생성된 이후가 맞는지 한 번 확인 부탁드립니다!
혹시 해결이 안되셨다면 관련 코드를 더 올려주시면 다시 확인해보겠습니다.(Map, Markers, Marker 등)

감사합니다 :)

bj2525님의 프로필 이미지
bj2525
질문자

먼저 답변 달아주셔서 감사합니다!

일단 Recoil로 해결이 되지 않아 Swr로 바꿔서 진행하고 있는 상황입니다. 그래도 다시 한 번 시도 해보고는 있는데, 같은 오류가 계속 발생하고 있습니다..

Marker 컴포넌트가 mount 되는 시점이 window.naver가 생성된 이후가 맞는지 확인 해달라고 해주셨는데, 제가 이해하기로는 Map 컴포넌트에 initalizeMap 함수 안에 window.naver 값이 생성된 이후에 Marker 컴포넌트가 mount되었나 라는 뜻으로 이해했습니다.

아래의 코드를 보면 Map컴포넌트 initializeMap 함수 안에서 naver.map에 대한 값을 setInitMap에 저장하고 전역적으로 저장한 값인 mapInfo를 Marker컴포넌트에서 가져다가 쓰고 있는 상황입니다. 다만 Swr을 사용할 때와의 차이점이 있다면 onLoad 함수를 Map 컴포넌트에 props로 넘겨주고 있는 부분이 있긴한데, 이 부분이 위에서 말씀해주신 Marker 컴포넌트가 mount 되는 시점이 window.naver가 생성된 이후여야되는 것과 상관이 있는지 모르겠지만 제 생각에는 해당 코드는 onLoad 함수를 호출 했을 때 Recoil가 마찬가지로 전역적으로 저장 하려고 쓴 부분이라고 생각됩니다! 혹시 틀렸다면.. 알려주시면 감사하겠습니다!!

// recoil 부분

import { NaverMapType } from '@/types/map'
import { atom } from 'recoil'

export const mapState = atom<NaverMapType | null>({
  key: 'mapState',
  default: null,
})

 

// Marker 컴포넌트

import { ImageIcon, NaverMapType } from '@/types/map'
import { Coordinates } from '@/types/store'
import { useEffect } from 'react'

interface IMarkerProps {
  map: NaverMapType
  coordinates: Coordinates
  onClick?: () => void
  icon: ImageIcon
}

const Marker = ({ map, coordinates, icon, onClick }: IMarkerProps): null => {
  useEffect(() => {
    let marker: naver.maps.Marker | null = null

    if (map) {
      marker = new naver.maps.Marker({
        map: map,
        position: new naver.maps.LatLng(...coordinates),
        icon,
      })

      if (onClick) {
        naver.maps.Event.addListener(marker, 'click', onClick)
      }
    }

    return () => {
      marker?.setMap(null)
    }
  }, [map])

  return null
}

export default Marker

 

// Markers 컴포넌트

import { STORE_KEY } from '@/hooks/useStore'
import { StoreInfo } from '@/types/store'
import useSWR from 'swr'
import React, { Fragment } from 'react'
import Marker from './Marker'
import { NaverMapType } from '@/types/map'
import { MAP_KEY } from '@/hooks/useMap'
import { generateStoreMarkerIcon } from '@/utils/generateMarker'
import useCurrentStore, { CURRENT_STORE_KEY } from '@/hooks/useCurrentStore'
import { useRecoilValue } from 'recoil'
import { mapState } from '@/recoil/atom/store'

const Markers = () => {
  const { data: storeList } = useSWR<StoreInfo[]>(STORE_KEY)
  // const { data: mapInfo } = useSWR<NaverMapType>(MAP_KEY)
  const mapInfo = useRecoilValue(mapState)

  const { data: targetStoreInfo } = useSWR<StoreInfo>(CURRENT_STORE_KEY)

  const { targetStore, clearStore } = useCurrentStore()

  if (!storeList || !mapInfo || !!targetStoreInfo) return null

  return (
    <Fragment>
      {targetStoreInfo && (
        <Marker
          map={mapInfo}
          coordinates={targetStoreInfo.coordinates}
          icon={generateStoreMarkerIcon(targetStoreInfo.season, true)}
          key={targetStoreInfo.nid}
          onClick={clearStore}
        />
      )}
      {storeList?.map((store) => {
        return (
          <Marker
            map={mapInfo}
            coordinates={store.coordinates}
            key={store.nid}
            icon={generateStoreMarkerIcon(store.season, false)}
            onClick={() => targetStore(store)}
          />
        )
      })}
    </Fragment>
  )
}

export default Markers
// Map 컴포넌트

const Map = ({
  mapId = 'map',
  initialCenter = INITIAL_CENTER,
  initialZoom = INITIAL_ZOOM,
}: IMapProps) => {
  const [initMap, setInitMap] = useRecoilState(mapState)
  const mapRef = useRef<NaverMapType | null>(null)

  const initializeMap = () => {
    const mapOptions = {
      center: new window.naver.maps.LatLng(...initialCenter),
      zoom: initialZoom,
      minZoom: 9,
      scaleContorl: false,
      mapDataControl: false,
      logoControlOptions: {
        position: naver.maps.Position.BOTTOM_LEFT,
      },
    }

    let map = new window.naver.maps.Map(mapId, mapOptions)
    mapRef.current = map

    setInitMap(map)
  }

  useEffect(() => {
    return () => {
      mapRef.current?.destroy()
    }
  }, [])

  return (
    <>
      <Script
        strategy="afterInteractive"
        type="text/javascript"
        src={`https://openapi.map.naver.com/openapi/v3/maps.js?ncpClientId=${process.env.NEXT_PUBLIC_NCP_CLIENT_ID}`}
        onReady={initializeMap}
      />
      <div id={mapId} style={{ width: '100%', height: '100%' }} />
    </>
  )
}

export default Map
박용주님의 프로필 이미지
박용주
지식공유자

넵넵 내용은 이해하신대로가 맞습니다!
올려주신 recoil 코드를 읽어봤는데 아직 이상한 부분이 보이지 않네요🤔 저 type error는 IDE에서도 뜨는 건가요? 아니면 브라우저에서만 뜨는 건가요?
(+ IDE에서 뜨는게 아니라면 build를 했을 때도 똑같이 오류가 뜨는지 확인 부탁드립니다)

bj2525님의 프로필 이미지
bj2525
질문자

build시에는 error가 발생하지 않고 브라우저에서만 error가 발생하고 있고 build 후에 npm run dev를 했는데도 여전히 error가 있습니다.

혹시나 해서 build 후에 npm run start 했는데 오류 없이 동작하고 있는 상황입니다..ㅎ

그런데 dev 환경에서는 오류가 나고 build후에 production환경에서는 오류가 안나는 건 어떤 차이인걸까요..?

박용주님의 프로필 이미지
박용주
지식공유자

음...recoil의 동작 방식이 개발환경과 배포환경이 다를 수도 있고, Next.js와 결합했을 때 그 문제가 드러나는 것 같기도 하네요🤔 콘솔에 뜨는 에러를 자세히 파보거나 recoil issue를 검색하는 등 디버깅을 더 해야할 문제로 보입니다.
제가 요새 개인 일이 바빠서 직접 더 알아보기가 힘들 것 같습니다ㅠㅠ 큰 도움이 되지 못해 죄송합니다🥲

bj2525님의 프로필 이미지
bj2525
질문자

넵 감사합니다 !

bj2525님의 프로필 이미지
bj2525

작성한 질문수

질문하기