TECH

React์—์„œ TMap API ์‚ฌ์šฉํ•˜๊ธฐ

ttaerrim 2023. 12. 30. 14:48

์ด ๊ธ€์—์„œ๋Š” ๋„ค์ด๋ฒ„ ๋ถ€์ŠคํŠธ์บ ํ”„ ๋‚ด์˜ ๋ชจ๊ฐ์ฝ” ๋ชจ์ง‘/๊ด€๋ฆฌ ํ”Œ๋žซํผ์ธ ๋ชจ๋ฝ ์„œ๋น„์Šค๋ฅผ ๊ฐœ๋ฐœํ•˜๋ฉฐ TMap API๋ฅผ ์‚ฌ์šฉํ–ˆ๋˜ ํ›„๊ธฐ๋ฅผ ๋‹ด์•„ ๋ณด์•˜์Šต๋‹ˆ๋‹ค. 

 

GitHub - boostcampwm2023/web17_morak: Morak | ๋„ค์ด๋ฒ„ ๋ถ€์ŠคํŠธ์บ ํ”„ ๋‚ด ๋ชจ๊ฐ์ฝ” ๋ชจ์ง‘/๊ด€๋ฆฌ ํ”Œ๋žซํผ ๐Ÿง‘๐Ÿป‍๐Ÿ’ป

Morak | ๋„ค์ด๋ฒ„ ๋ถ€์ŠคํŠธ์บ ํ”„ ๋‚ด ๋ชจ๊ฐ์ฝ” ๋ชจ์ง‘/๊ด€๋ฆฌ ํ”Œ๋žซํผ ๐Ÿง‘๐Ÿป‍๐Ÿ’ป๐Ÿ‘ฉ๐Ÿป‍๐Ÿ’ป๐Ÿ‘จ๐Ÿป‍๐Ÿ’ป. Contribute to boostcampwm2023/web17_morak development by creating an account on GitHub.

github.com

 
 
TMAP Open API๋Š” ์›น ๊ฐœ๋ฐœ ๋˜๋Š” ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜ ๊ฐœ๋ฐœ์— ๋‹ค์–‘ํ•˜๊ฒŒ ํ™œ์šฉ๋  ์ˆ˜ ์žˆ๋„๋ก, Javascript ํ˜•ํƒœ๋กœ ์ œ๊ณต๋˜๋Š” TMAP ์ง€๋„ ํ”Œ๋žซํผ์ž…๋‹ˆ๋‹ค. TMap API๋Š” ์ด๋ฏธ์ง€๋กœ ์ง€๋„๋ฅผ ๊ทธ๋ฆฌ๋Š” Raster Map(V2)๊ณผ ์‹ค์‹œ๊ฐ„์œผ๋กœ ์ง€๋„๋ฅผ ๊ทธ๋ฆฌ๋Š” Vector Map(V3) ๋‘ ๊ฐ€์ง€๋ฅผ ์ง€์›ํ•˜๋ฉฐ Vector Map์€ ํ™•๋Œ€/์ถ•์†Œ๊ฐ€ ์ž์—ฐ์Šค๋Ÿฝ๊ณ  ํšŒ์ „ ๊ธฐ๋Šฅ์ด ์žˆ๋Š” ์ฐจ์ด์ ์ด ์žˆ๋‹ค๊ณ  ํ•˜๋‹ˆ ์ฐธ๊ณ ํ•˜์‹œ๋ฉด ์ข‹์„ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค. ์ง์ ‘ ์‚ฌ์šฉํ•ด ๋ณด์•˜์„ ๋•Œ๋Š” ์ง€์›ํ•˜๋Š” ๊ธฐ๋Šฅ์€ Raster Map์ด ๋” ๋งŽ์•˜์Šต๋‹ˆ๋‹ค.
 
๋˜ํ•œ, ์ด ๊ธ€์—์„œ ์„ค๋ช…ํ•˜๋Š” ๋ฐฉ์‹์€ Raster Map ๋ฐฉ์‹์ธ TMapv2๋ฅผ ์‚ฌ์šฉํ–ˆ์Šต๋‹ˆ๋‹ค. TMapv3์— ์ ์šฉํ•  ๋•Œ๋Š” ๋ฉ”์†Œ๋“œ๋ช…์ด๋‚˜ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ์‹์ด ๋‹ค๋ฅผ ์ˆ˜ ์žˆ์œผ๋‹ˆ, ์ž์„ธํ•œ ์‚ฌํ•ญ์€ TMap์˜ ๊ณต์‹ ๋ฌธ์„œ๋ฅผ ์ฐธ๊ณ ํ•ด ์ฃผ์„ธ์š”.
 
 
 
 

๊ธฐ๋Šฅ ์„ค๋ช…

๋ชจ๋ฝ์—์„œ๋Š” ๋ชจ๊ฐ์ฝ”๋ฅผ ์ฃผ์ตœํ•  ๊ฒฝ์šฐ ํผ์„ ์ž‘์„ฑํ•˜์—ฌ ๊ธ€์„ ๋“ฑ๋กํ•ฉ๋‹ˆ๋‹ค. ํผ ์ž‘์„ฑ ์‹œ ์ฃผ์†Œ๋ฅผ ์ž…๋ ฅํ•˜๋Š” ๋ถ€๋ถ„์ด ์žˆ๋Š”๋ฐ, ์ด ๋ถ€๋ถ„์„ ๋‹จ์ˆœ ํ…์ŠคํŠธ๊ฐ€ ์•„๋‹Œ ์ฃผ์†Œ ํ˜•์‹์˜ ํ…์ŠคํŠธ๋กœ ์ž…๋ ฅ๋ฐ›๊ธฐ ์œ„ํ•ด TMap API๋ฅผ ์‚ฌ์šฉํ–ˆ์Šต๋‹ˆ๋‹ค.
 
 
 

 

์ง€๋„ ๋„์šฐ๊ธฐ

import { useEffect, useState } from 'react';

import { TMap } from '@/types';

const { Tmapv2 } = window;

export const useMap = (mapRef: React.RefObject<HTMLDivElement>) => {
  const [mapInstance, setMapInstance] = useState<TMap | null>(null);

  useEffect(() => {
    if (mapRef.current?.firstChild || mapInstance) {
      return;
    }

    const map = new Tmapv2.Map('map', {
      zoom: DEFAULT_ZOOM_LEVEL,
      zoomControl: false,
      center: new Tmapv2.LatLng(INITIAL_LATITUDE, INITIAL_LONGITUDE),
    });

    map.setZoomLimit(MIN_ZOOM_LEVEL, MAX_ZOOM_LEVEL);
    setMapInstance(map);
  }, [mapRef, mapInstance]);

};

 
 

์šฐ์„  ์ง€๋„๋Š” ๋ Œ๋”๋งํ•  ๊ฒƒ ํ•˜๋‚˜๋งŒ ๋„์šฐ๋ฉด ๋ฉ๋‹ˆ๋‹ค. ์ง€๋„๋ฅผ ๋„์šฐ๊ธฐ ์œ„ํ•œ useMap ํ›…์„ ์ž‘์„ฑํ–ˆ์Šต๋‹ˆ๋‹ค.

 

useMap์˜ ์ธ์ž์ธ mapRef๋Š” ์„ค์ •ํ•œ ์ง€๋„์™€ div ํƒœ๊ทธ๋ฅผ ์—ฐ๊ฒฐํ•ด ์ฃผ๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉํ–ˆ์Šต๋‹ˆ๋‹ค. 

 

๋˜ํ•œ ์ดํ›„์— new Tmapv2.Map๋กœ ์ƒ์„ฑํ•œ map ๋ณ€์ˆ˜์— ์ ‘๊ทผํ•˜์—ฌ ์ง€๋„๋ฅผ ์กฐ์ž‘ํ•  ํ•„์š”๊ฐ€ ์žˆ๋Š”๋ฐ, ์ด๋ฅผ ์œ„ํ•ด mapInstance state๋ฅผ ๋งŒ๋“ค์–ด ์ €์žฅํ•ด ๋‘์—ˆ์Šต๋‹ˆ๋‹ค.

 

useEffect ๋‚ด์˜ if ๋ฌธ์—์„œ mapRef.current?.firstChild์™€ mapInstance๋ฅผ ๊ฒ€์‚ฌํ•œ ์ด์œ ๋Š”, ์ง€๋„ ๊ฐ์ฒด๊ฐ€ ๋‘ ๊ฐœ ์ƒ์„ฑ๋˜๋Š” ๋ฒ„๊ทธ๊ฐ€ ๋ฐœ์ƒํ•˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ์žˆ์—ˆ๊ธฐ ๋•Œ๋ฌธ์— ๋‹ค์Œ ํฌ์ŠคํŒ…์„ ์ฐธ๊ณ ํ•˜์—ฌ ํ•ด๊ฒฐํ–ˆ์Šต๋‹ˆ๋‹ค.

 
 

๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋ฐฉ์‹์œผ๋กœ ๋ชจ๋‹ฌ์— ์ง€๋„๋ฅผ ๋„์šธ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
 

 

 
 

๊ฒ€์ƒ‰์–ด๋กœ ์žฅ์†Œ ์„ ํƒํ•˜๋ฉด ์ง€๋„์— ํ•€์œผ๋กœ ๋ณด์—ฌ ์ฃผ๊ธฐ

์žฅ์†Œ ๋ชจ๋‹ฌ์˜ ์™ผ์ชฝ ์ƒ๋‹จ์˜ ์ธํ’‹์— ์žฅ์†Œ ํ‚ค์›Œ๋“œ๋ฅผ ๊ฒ€์ƒ‰ํ•˜๋ฉด ๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ๊ฐ€ ๋ฆฌ์ŠคํŠธ ํ˜•์‹์œผ๋กœ ์ถœ๋ ฅ๋˜๋ฉฐ, ๋ฆฌ์ŠคํŠธ ๋‚ด์˜ ์•„์ดํ…œ์„ ํด๋ฆญํ•˜๋ฉด ์žฅ์†Œ๊ฐ€ ์„ ํƒ๋ฉ๋‹ˆ๋‹ค. ์‚ฌ์šฉ์ž์—๊ฒŒ ์„ ํƒํ•œ ์žฅ์†Œ๋ฅผ ์ง€๋„ ๋‚ด์—์„œ๋„ ๋ณด์—ฌ ์ฃผ๊ธฐ ์œ„ํ•ด ํ•€์œผ๋กœ ํ‘œ์‹œํ•ด ์ฃผ๋Š” ๊ธฐ๋Šฅ์„ ๊ตฌํ˜„ํ–ˆ์Šต๋‹ˆ๋‹ค.
 
 

import { useCallback, useEffect, useState } from 'react';

import { Marker } from '@/components/Map/Marker';
import { TMap, TMapMarker } from '@/types';

const { Tmapv2 } = window;

export const useMap = (mapRef: React.RefObject<HTMLDivElement>) => {
  const [mapInstance, setMapInstance] = useState<TMap | null>(null);
  const [currentMarker, setCurrentMarker] = useState<TMapMarker | null>(null);

  // ์ง€๋„ ๋„์šฐ๋Š” ์ฝ”๋“œ ์ƒ๋žต

  const updateMarker = useCallback(
    (coord: { latitude: number | null; longitude: number | null }) => {
      const { latitude, longitude } = coord;
      if (!(latitude && longitude) || !mapInstance) {
        return;
      }

      if (currentMarker) {
        const { _lat: prevLatitude, _lng: prevLongitude } =
          currentMarker.getPosition();
        if (prevLatitude === latitude && prevLongitude === longitude) {
          return;
        }
      }

      currentMarker?.setMap(null);
      const position = new Tmapv2.LatLng(latitude, longitude);
      const marker = new Tmapv2.Marker({
        position,
        map: mapInstance,
        icon: markerIcon,
        iconSize: new Tmapv2.Size(50, 50),
      })
      
      setCurrentMarker(marker);
      mapInstance?.setCenter(position);
    },
    [mapInstance, currentMarker],
  );

  return { mapInstance, updateMarker };
};

 

์šฐ์„  useMap ํ›…์—์„œ ์žฅ์†Œ์˜ ์„ ํƒ์— ๋”ฐ๋ผ ์ง€๋„์— ๋งˆ์ปค๋ฅผ ์ฐ์–ด ์ฃผ๋Š” updateMarker๋ผ๋Š” ๋ฉ”์†Œ๋“œ๋ฅผ ๋งŒ๋“ค์—ˆ์Šต๋‹ˆ๋‹ค.

 

updateMarker์—์„œ๋Š” ์ธ์ž๋กœ ๋ฐ›์€ coord์˜ ์œ„๋„/๊ฒฝ๋„์™€ ์ด๋ฏธ ์ฐํ˜€์ ธ ์žˆ๋Š” marker์˜ ์œ„๋„/๊ฒฝ๋„ ๊ฐ’์„ ๋น„๊ตํ•ฉ๋‹ˆ๋‹ค.

 

์ธ์ž๋กœ ๋ฐ›์€ coord๊ฐ€ ์œ ํšจํ•˜์ง€ ์•Š๊ฑฐ๋‚˜, coord๊ฐ€ ๋ณ€๊ฒฝ๋˜์ง€ ์•Š์•˜๋‹ค๋ฉด updateMarker๋Š” ๋งˆ์ปค์˜ ์œ„์น˜๋ฅผ ๋ณ€๊ฒฝํ•˜๋Š” ๋กœ์ง์„ ์‹คํ–‰ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

 

๋งŒ์ผ coord์˜ ์œ„๋„/๊ฒฝ๋„๊ฐ€ ๋ณ€๊ฒฝ๋˜์—ˆ๋‹ค๋ฉด, currentMarker.setMap(null)๋กœ ๋งˆ์ปค๋ฅผ ์ง€๋„์—์„œ ์ง€์šฐ๊ณ  ์ƒˆ๋กœ์šด ์ปค์Šคํ…€ ๋งˆ์ปค๋ฅผ ์ง€๋„์— ์ถ”๊ฐ€ํ•ด ์ค๋‹ˆ๋‹ค. 

๊ทธ๋ฆฌ๊ณ  mapInstance.setCenter(position)์œผ๋กœ ์ƒˆ๋กœ ์ฐ์€ ๋งˆ์ปค๊ฐ€ ์ง€๋„ ์ค‘์•™์— ํ‘œ์‹œ๋˜๋„๋ก ๋ณด์—ฌ ์ค๋‹ˆ๋‹ค.

 

TMapLatLng์™€ ๊ฐ™์€ ํƒ€์ž…์€ TMap API Guide๋ฅผ ์ฐธ๊ณ ํ•˜์—ฌ ์ƒ์„ฑํ–ˆ์Šต๋‹ˆ๋‹ค.

 
 

๊ทธ๋ฆฌ๊ณ  ๋งต ๋ชจ๋‹ฌ์—์„œ๋Š” useMap ํ›…์˜ updateMarker ๋ฉ”์†Œ๋“œ๋ฅผ ์ด์šฉํ•ฉ๋‹ˆ๋‹ค.

์šฐ์„  ์žฅ์†Œ ๋ฆฌ์ŠคํŠธ ์ค‘ ํ•˜๋‚˜์˜ ์žฅ์†Œ๋ฅผ ์„ ํƒํ•˜๊ธฐ ์œ„ํ•ด ํด๋ฆญํ•˜๋ฉด onClickAddressListItem ๋ฉ”์†Œ๋“œ๊ฐ€ ํ˜ธ์ถœ๋ฉ๋‹ˆ๋‹ค. ํ•ด๋‹น ๋ฉ”์†Œ๋“œ๋Š” coord์— ์„ ํƒํ•œ ์žฅ์†Œ์˜ ์œ„๋„์™€ ๊ฒฝ๋„๋ฅผ ์ €์žฅํ•ฉ๋‹ˆ๋‹ค.

import { useEffect, useRef, useState } from "react";
import { useMap } from "./useMap";

export function MapModal() {
  const [selectedAddress, setSelectedAddress] = useState("");
  const [coord, setCoord] = useState<{
    latitude: number | null;
    longitude: number | null;
  }>({
    latitude: null,
    longitude: null,
  });
  const mapRef = useRef<HTMLDivElement>(null);
  const { updateMarker } = useMap(mapRef);

  useEffect(() => {
    updateMarker(coord);
  }, [coord, updateMarker]);

  const onClickAddressListItem = <
    Event extends React.MouseEvent | React.KeyboardEvent,
  >(
    e: Event,
  ) => {
    setSelectedAddress(e.currentTarget.getAttribute("value") || "");
    const coordinate = {
      latitude: Number(e.currentTarget.getAttribute("data-lat")),
      longitude: Number(e.currentTarget.getAttribute("data-lon")),
    };

    setCoord(coordinate);
  };

  return (
   // ์ƒ๋žต
  );
}

 

๊ทธ๋ฆฌ๊ณ  coord๊ฐ€ ๋ณ€๊ฒฝ๋˜์—ˆ๋‹ค๋ฉด, updateMarker๋ฅผ ํ˜ธ์ถœํ•ด ์ง€๋„์˜ ๋งˆ์ปค๋ฅผ ๋ณ€๊ฒฝํ•ฉ๋‹ˆ๋‹ค.

 
 

 
๋‹ค์Œ๊ณผ ๊ฐ™์ด ์žฅ์†Œ ๋ฆฌ์ŠคํŠธ๋ฅผ ํด๋ฆญํ–ˆ์„ ๋•Œ ์ง€๋„์˜ ๋งˆ์ปค๋ฅผ ๋„์šธ ์ˆ˜ ์žˆ๊ฒŒ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.
 
 
 
 

์ง€๋„ ํด๋ฆญ ์‹œ ๋งˆ์ปค ๋„์šฐ๊ธฐ

์žฅ์†Œ๋ฅผ ํ…์ŠคํŠธ๋กœ ๊ฒ€์ƒ‰ํ•˜๋Š” ๊ฒƒ ์™ธ์—๋„ ์ง€๋„๋ฅผ ํด๋ฆญํ•˜์—ฌ ์›ํ•˜๋Š” ์žฅ์†Œ๋ฅผ ์„ ํƒํ•  ์ˆ˜ ์žˆ๋Š” ๊ธฐ๋Šฅ์„ ๊ตฌํ˜„ํ–ˆ์Šต๋‹ˆ๋‹ค.
 

 
 
 
 
T Map ํด๋ฆญํ•œ ์œ„์น˜์— ๋งˆ์ปค ํ‘œ์‹œํ•˜๊ธฐ ์˜ˆ์‹œ์— ๋‚˜์˜จ ๋Œ€๋กœ ๊ตฌํ˜„์„ ์‹œ๋„ํ–ˆ์œผ๋‚˜, ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๋งˆ์ปค๊ฐ€ ์—ฌ๋Ÿฌ ๊ฐœ ์ฐํžˆ๋Š” ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค.
 

 

๋”ฐ๋ผ์„œ ์˜ˆ์‹œ์™€ ๊ฐ™์€ ๋ฐฉ์‹์ด ์•„๋‹Œ currentMarker๋กœ ๋งˆ์ปค๋ฅผ ๊ด€๋ฆฌํ•˜๊ณ , ๋งˆ์ปค์˜ position์„ ๋ฐ”๊พธ์–ด ์ƒˆ๋กœ์šด ์œ„์น˜์— ๋งˆ์ปค๋ฅผ ์ฐ์–ด ์ฃผ๋Š” ๋ฐฉํ–ฅ์œผ๋กœ ๊ตฌํ˜„ํ–ˆ์Šต๋‹ˆ๋‹ค.

 
 
์ฝ”๋“œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

import { useEffect, useState } from "react";

import { Marker } from "@/components/Map/Marker";
import { TMap, TMapMarker } from "@/types";

const { Tmapv2 } = window;

export const useMap = (mapRef: React.RefObject<HTMLDivElement>) => {
  const [mapInstance, setMapInstance] = useState<TMap | null>(null);
  const [currentMarker, setCurrentMarker] = useState<TMapMarker | null>(null);

  useEffect(() => {
    if (!mapInstance) {
      return;
    }

    mapInstance.addListener("Click", (e) => {
      const { latLng } = e;
      const position = new Tmapv2.LatLng(latLng.lat(), latLng.lng());

      if (!currentMarker) {
        const marker = new Tmapv2.Marker({
            position,
            map: mapInstance,
            icon: markerIcon,
            iconSize: new Tmapv2.Size(50, 50),
          })
        setCurrentMarker(marker);
      } else {
        currentMarker.setPosition(position);
      }
    });
  }, [mapInstance, currentMarker]);
};

 

์—ฌ๊ธฐ์„œ currentMarker๊ฐ€ ์—†๋‹ค๋ฉด ์ƒˆ๋กœ์šด ๋งˆ์ปค๋ฅผ ์ƒ์„ฑํ•˜์—ฌ setCurrentMarker์— ํ• ๋‹นํ•˜๊ณ , 

currentMarker๊ฐ€ ์žˆ๋‹ค๋ฉด setPosition ๋ฉ”์†Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•ด ๋งˆ์ปค์˜ ํฌ์ง€์…˜๋งŒ ๋ฐ”๊ฟ”์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ๊ตฌํ˜„ํ–ˆ์Šต๋‹ˆ๋‹ค.

 
 
 
 
 
 
๊ทธ๋Ÿฌ๋‚˜ ์ด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ณ  ๋‚˜๋‹ˆ, ๋˜ ๋‹ค๋ฅธ ๋ฌธ์ œ์— ์ง๋ฉดํ–ˆ์Šต๋‹ˆ๋‹ค. (๋ฒ„๊ทธ ์ณ‡๋ฐ”ํ€ด...)
์žฅ์†Œ ํด๋ฆญ ์‹œ ์ƒ๊ธฐ๋Š” ๋งˆ์ปค์™€ ์ง€๋„ ํด๋ฆญ ์‹œ ์ƒ๊ธฐ๋Š” ๋งˆ์ปค๊ฐ€ ๋”ฐ๋กœ ์กด์žฌํ•œ๋‹ค๋Š” ๋ฌธ์ œ๋„ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค.
 

 
 

์ด๋ฅผ ์œ„ํ•ด ์ง€๋„๋‚˜ ์žฅ์†Œ๋ฅผ ํด๋ฆญํ•˜์—ฌ ์„ ํƒํ•œ ์ฃผ์†Œ๋ฅผ ๋ณ€๊ฒฝํ•  ๊ฒฝ์šฐ currentCoord(์œ„๋„/๊ฒฝ๋„) ๊ฐ’์„ ๋ฐ”๊พธ๊ณ , currentCoord๊ฐ€ ๋ณ€๊ฒฝ๋˜์—ˆ์„ ๋•Œ ๋ณ€๊ฒฝ๋œ ์œ„๋„/๊ฒฝ๋„์— ๋งˆ์ปค๋ฅผ ์ฐ์–ด ์ฃผ๋„๋ก ๋กœ์ง์„ ๋ณ€๊ฒฝํ•˜์—ฌ ์žฅ์†Œ ์„ ํƒ ๊ธฐ๋Šฅ์„ ์™„์„ฑํ–ˆ์Šต๋‹ˆ๋‹ค.

 

import { useEffect, useState } from 'react';

import { TMap, TMapEvent, TMapLatLng, TMapMarker } from '@/types';

const { Tmapv2 } = window;

export const useMap = (mapRef: React.RefObject<HTMLDivElement>) => {
  const [mapInstance, setMapInstance] = useState<TMap | null>(null);
  const [currentMarker, setCurrentMarker] = useState<TMapMarker | null>(null);
  const [currentCoord, setCurrentCoord] = useState<TMapLatLng | null>(null);

  useEffect(() => {
    if (!currentCoord) {
      return;
    }

    const makeMarker = (position: TMapLatLng) => {
      if (!mapInstance) {
        return;
      }

      currentMarker?.setMap(null);
      
      const marker = new Tmapv2.Marker({
         position,
         map: mapInstance,
         icon: markerIcon,
         iconSize: new Tmapv2.Size(50, 50),
      })

      setCurrentMarker(marker);
    };

    makeMarker(currentCoord);
  }, [currentCoord, mapInstance]);

  useEffect(() => {
    if (!mapInstance) {
      return;
    }

    const changeCoord = (e: TMapEvent) => {
      const { latLng } = e;
      const position = new Tmapv2.LatLng(latLng.lat(), latLng.lng());

      setCurrentCoord(position);
    };

    mapInstance.addListener('click', changeCoord);
  }, [mapInstance, currentCoord]);
};

 
 
 
 
 
 

ํ›„๊ธฐ

๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ง€๋„ API๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์„œ๋น„์Šค์˜ ๊ธฐ๋Šฅ์„ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค. TypeScript๋ฅผ ์ง€์›ํ•˜์ง€ ์•Š๋Š” API์˜ ํƒ€์ž…์„ ์ผ์ผ์ด ์ž‘์„ฑํ•˜์—ฌ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ๋„ ์ฒ˜์Œ์—” ๊นŒ๋‹ค๋กœ์› ๊ณ , JavaScript์˜ ์˜ˆ์‹œ๋ฅผ React์— ์ ์šฉํ•˜๋ ค๋‹ค ๋ณด๋‹ˆ ์–ด๋ ค์šด ์ ๋„ ๋งŽ์•˜์ง€๋งŒ ๋ฌธ์ œ๋ฅผ ํŒŒ์•…ํ•˜๊ณ  ๋ถ„์„ํ•˜๋ฉฐ ๋‹ค๋ฅธ ํ•ด๊ฒฐ ๋ฐฉ์•ˆ์„ ๋ชจ์ƒ‰ํ•˜๋Š” ๊ธธ์„ ํ†ตํ•ด ํ•œ ๊ฑธ์Œ ๋” ์„ฑ์žฅํ•  ์ˆ˜ ์žˆ๋Š” ๊ณ„๊ธฐ๊ฐ€ ๋˜์ง€ ์•Š์•˜๋‚˜ ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. 
 
TMap API๋ฅผ React์— ์ ์šฉํ•˜๋Š” ๊ธ€์ด ๋งŽ์ง€ ์•Š์•˜๊ธฐ ๋•Œ๋ฌธ์—, ์ €์˜ ํฌ์ŠคํŒ…์œผ๋กœ ์กฐ๊ธˆ์ด๋‚˜๋งˆ ๋„์›€์ด ๋  ์ˆ˜ ์žˆ์—ˆ์œผ๋ฉด ์ข‹๊ฒ ์Šต๋‹ˆ๋‹ค. ์ž์„ธํ•œ ์ฝ”๋“œ๋ฅผ ์‚ดํŽด๋ณด๊ณ  ์‹ถ์œผ์‹œ๋‹ค๋ฉด ๋ฆฌํŒฉํ† ๋ง ์ค‘์ธ ์ฝ”๋“œ์ง€๋งŒ ์ฐธ๊ณ ํ•ด ์ฃผ์‹œ๊ณ  โฌ‡๏ธโฌ‡๏ธโฌ‡๏ธ ๋” ๋งŽ์€ ๋„์›€์ด ํ•„์š”ํ•˜์‹œ๊ฑฐ๋‚˜ ํ”ผ๋“œ๋ฐฑ์„ ์ฃผ๊ณ  ์‹ถ๋‹ค๋ฉด ๋Œ“๊ธ€๋กœ ์˜๊ฒฌ์„ ๋‚จ๊ฒจ ์ฃผ์…”๋„ ์ข‹์Šต๋‹ˆ๋‹ค!
 
https://github.com/boostcampwm2023/web17_morak/blob/develop/app/frontend/src/hooks/useMap.ts