Next.jsでGoogle Mapsを表示する方法

# はじめに
この記事では、Next.jsアプリケーションでGoogle Maps APIを使用して地図を表示する方法について説明します。具体的には、Material-UIを使用したコンポーネント構成と、Google Maps APIの非同期読み込みを実装します。

# 環境設定
Google Maps APIのキーを取得し、環境変数に設定します。.env.localファイルに以下のように記載します。
```.env.local
NEXT_PUBLIC_GOOGLE_MAP_KEY=your_google_maps_api_key
```

# ファイル構成
以下は、この記事で紹介したNext.jsアプリケーションのファイル構成です。
```
my-next-app/
├── .env.local　//環境変数を記入
├── package.json
├── tsconfig.json
├── next.config.js
├── src/
│   ├── pages/
│   │   └── index.tsx
│   └── utils/
│       ├── loadGoogleMapsAPI.ts
│       └── initMap.ts
├── public/
│   └── (静的ファイルがあればここに配置)
└── (その他の設定ファイルやディレクトリ)

```


# コンポーネントの作成
以下のコードは、Next.jsでGoogle Mapsを表示するコンポーネントの実装です。

## index.tsx
index.tsxファイルは、地図を表示するメインコンポーネントです。

```index.tsx
import { Box, Container } from '@mui/material'
import type { NextPage } from 'next'
import { useEffect, useState } from 'react'
import { loadGoogleMapsAPI } from '@/utils/loadGoogleMapsAPI'

const Index: NextPage = () => {
  const [map, setMap] = useState<google.maps.Map | null>(null)

  useEffect(() => {
    loadGoogleMapsAPI(setMap)
  }, [])

  return (
    <>
      <Container maxWidth="xl">
        <Box id="map" style={{ height: '80vh', width: '100%' }}></Box>
      </Container>
    </>
  )
}

export default Index
```

## loadGoogleMapsAPI.ts
次に、Google Maps APIを非同期に読み込む関数を実装します。この関数は、APIの読み込みが完了した後に地図を初期化します。

```loadGoogleMapsAPI.ts
import { initMap } from './initMap'

interface GoogleMapsConfig {
  key?: string // オプショナルに変更
  v: string
  [key: string]: string | undefined // インデックスシグネチャを追加
}

export const loadGoogleMapsAPI = (
  setMap: React.Dispatch<React.SetStateAction<google.maps.Map | null>>,
) => {
  ;((g: GoogleMapsConfig) => {
    let h: Promise<void> | null = null
    const p = 'The Google Maps JavaScript API'
    const c = 'google'
    const l = 'importLibrary'
    const q = '__ib__'
    const m = document

    let b: any = window
    b = b[c] || (b[c] = {})
    const d = b.maps || (b.maps = {})
    const e = new URLSearchParams()

    const u = () => {
      if (!h) {
        //GoogleMapsAPIのスクリプトが読み込まれるのを待つ
        h = new Promise<void>((resolve, reject) => {
          const a = m.createElement('script') as HTMLScriptElement
          //クエリパラメータの設定キー バリュー
          e.set('libraries', '')
          for (const k in g) {
            if (g[k]) {
              e.set(
                k.replace(/[A-Z]/g, (t) => '_' + t[0].toLowerCase()),
                g[k] as string,
              )
            }
          }
          e.set('callback', c + '.maps.' + q)
          //Google Maps APIのURLとクエリパラメータを設定
          a.src = `https://maps.${c}apis.com/maps/api/js?` + e
          //resolve
          d[q] = resolve
          //rejects
          a.onerror = () => reject(new Error(p + ' could not load.'))
          //ドキュメントの属性を検索
          a.nonce =
            (m.querySelector('script[nonce]') as HTMLScriptElement)?.nonce || ''
          //document.head要素に新しいscript要素aを追加
          m.head.append(a)
        })
      }
      //Promiseをリターンする
      return h
    }

    if (!d[l]) {
      d[l] = (f: string, ...n: any[]) => u().then(() => d[l](f, ...n))
      return u().then(() => {
        // マップを表示する
        initMap(setMap)
      })
    }
  })({
    key: process.env.NEXT_PUBLIC_GOOGLE_MAP_KEY,// 環境変数
    v: 'beta',
  })
}

```
## initMap.ts
最後に、地図を初期化する関数を実装します。この関数は、指定されたDOM要素にGoogle Mapを表示します。

```initMap.ts
export const initMap = async (
  setMap: React.Dispatch<React.SetStateAction<google.maps.Map | null>>,
) => {
  const mapElement = document.getElementById('map')

  if (mapElement) {
    const map = new google.maps.Map(mapElement, {
      zoom: 16,
      mapId: 'DEMO_MAP_ID',
      maxZoom: 25,
      center: { lat: 35.681236, lng: 139.767125 },//東京駅を中心
    })

    setMap(map)
  } else {
    console.error('Google Maps API is not available')
  }
}
```

# GoogleMapの表示
[![Image from Gyazo](https://i.gyazo.com/be52dd748bc1ec465dae2acb49bba6cb.jpg)](https://gyazo.com/be52dd748bc1ec465dae2acb49bba6cb)

# 結論
以上で、Next.jsアプリケーションにGoogle Mapsを統合する方法について説明しました。これにより、Google Mapsを使用した地図表示が簡単に実現できます。ぜひ、ご自身のプロジェクトに取り入れてみてください。