備忘録

備忘録

ReactでGoogleMAP利用する方法

Ⅰ. はじめに

タイトルの通り「ReactでGoogleMAP利用する方法」です。

Ⅱ. 手順

1. Google MAP PlatformのAPIキーを生成する

https://console.cloud.google.com/google/maps-apis/credentials

2. 必要なライブラリをインストールする
npm install @googlemaps/js-api-loader
npm install @types/google.maps
3. サンプルプログラムを書く
import { Loader } from '@googlemaps/js-api-loader'
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';

const GoogleMapApiKey = 'YOUR_GOOGLE_MAP_API_KEY'
const GoogleMapPosition: google.maps.LatLngLiteral = { lat: 35.6812362, lng: 139.7645499 } // 東京駅

export default function App(): JSX.Element {
  const mapRef = useRef<HTMLDivElement>(null)

  const [mapsLibrary, setMapsLibrary] = useState<google.maps.MapsLibrary>()
  const [markerLibrary, setMarkerLibrary] = useState<google.maps.MarkerLibrary>()
  const [geocodingLibrary, setGeocodingLibrary] = useState<google.maps.GeocodingLibrary>()
  const [map, setMap] = useState<google.maps.Map>()
  const [address, setAddress] = useState<string>('')
  const [markers, setMarkers] = useState<google.maps.marker.AdvancedMarkerElement[]>([])

  const loader = useMemo(() => new Loader({
    apiKey: GoogleMapApiKey,
    version: '3',
    libraries:['maps']
  }), [])

  /**
   * マーカーを追加する
   */
  const addMarker = useCallback((position: google.maps.LatLngLiteral | google.maps.LatLng, title: string): void => {
    if (!markerLibrary) {
      console.log('markerLibrary is null')
      return
    }

    const marker = new markerLibrary.AdvancedMarkerElement({
      map: map,
      position: position,
      title: title
    })

    setMarkers((markers) => [...markers, marker])
  }, [map, markerLibrary])

  /**
   * マーカーを全て削除する
   */
  function clearAllMarker(): void {
    for (const marker of markers) {
      marker.map = null
    }
  }

  useEffect(() => {
    async function asyncFunction() {
      const mapsLibrary = await loader.importLibrary('maps')
      const markerLibrary = await loader.importLibrary('marker')
      const geocodingLibrary = await loader.importLibrary('geocoding')
      setMapsLibrary(mapsLibrary)
      setMarkerLibrary(markerLibrary)
      setGeocodingLibrary(geocodingLibrary)
    }

    asyncFunction()
  }, [loader])

  useEffect(() => {
    if (!mapsLibrary) {
      return
    }

    // Google Mapを描画する
    const map = new mapsLibrary.Map(mapRef.current!, {
      center: GoogleMapPosition,
      zoom: 6,
      mapId: 'DEMO_MAP_ID'
    })
    setMap(map)
  }, [mapsLibrary])

  useEffect(() => {
    if (!markerLibrary) {
      return
    }

    // マーカーを描画する
    addMarker(GoogleMapPosition, 'Title001')
  }, [markerLibrary, addMarker])

  async function onFormSubmit(e: React.FormEvent<HTMLFormElement>): Promise<void> {
    e.preventDefault()

    if (!geocodingLibrary) {
      return
    }

    const request: google.maps.GeocoderRequest = {
      address: address
    }
    const result = await new geocodingLibrary.Geocoder().geocode(request)
    if (result.results.length > 0) {
      if (!map) {
        return
      }

      const location = result.results[0].geometry.location

      // 地図の中心座標を変更する
      map.setCenter(location)

      // マーカーを描画する
      addMarker(location, address)
    }
  }

  return (
    <>
      <form onSubmit={(e) => onFormSubmit(e)}>
        <label htmlFor="address">住所</label>
        <input type="text" id="address" value={address} onChange={(e) => setAddress(e.target.value)} />
        <button type="submit">送信</button>
      </form>

      <div>
        <button onClick={() => clearAllMarker()}>マーカー全削除</button>
      </div>

      <div ref={mapRef} style={{ width: '500px', height: '500px' }}></div>
    </>
  )
}

実行結果