ReactでGoogle Map実装を極限まで楽にするライブラリ「react-easy-google-map」を公開しました

スポンサーリンク

Reactを使ったWebアプリケーションの開発で、「Google Map上に現在地(中心)のピンを立てて、その周りにいくつかのスポットのピンを配置し、クリックしたら吹き出し(InfoWindow)を出す」という要件、よくありますよね。

OSSの @vis.gl/react-google-maps は非常に高機能で素晴らしいライブラリですが、シンプルに使いたいだけなのに状態管理やボイラープレート(お決まりの記述)が多くなりがちという課題を感じていました。

そこで、もっと直感的に、設定データ(JSON)を渡すだけで爆速でよくある要件のGoogle Mapを実装できるラッパーライブラリ「react-easy-google-mapを開発・公開しました!

この記事では、開発の背景と、このライブラリを使うことでどれくらい実装が楽になるのかをご紹介します。

なぜ作ったのか?(開発の背景)

前述の既存ライブラリ @vis.gl/react-google-maps を使って、前述のような「中心マーカー+周辺マーカー + InfoWindow」を実装しようとすると、以下のようなハードルがあります。

  1. 状態管理の複雑さ:
    InfoWindowを出すために、どのピンがクリックされたかを useStateで管理し、他のピンがクリックされたら閉じる制御を自前で書く必要がある。
  2. Refの管理:
    InfoWindowを正しいマーカーに紐付けるために、各マーカーの useAdvancedMarkerRef
    を取得して管理しなければならない。
  3. コードの肥大化:
    結果として、コンポーネント内にMap用のロジックが散乱し、コードの見通しが悪くなる。

「地図アプリを作るわけではないのだから、もっと手軽にデータを渡すだけで完結させたい」
その思いから、状態管理やRefの紐付けをライブラリ内部に隠蔽し、開発者が「中心点」と「表示したいデータ」の定義だけに集中できる構成を目指しました。

どれくらい実装が楽になるのか?(コード比較)

同じ要件(中心に青いマーカーを置き、周辺に赤いマーカーを配置。クリックでInfoWindowを開く)を実装する場合のコードを比較してみます。


Before: @vis.gl/react-google-maps をそのまま使った場合

状態管理(useState)やマーカーのRef管理が必要になり、コンポーネントが長くなってしまいます。

import React, { useState } from 'react';
import { APIProvider, Map, AdvancedMarker, Pin, InfoWindow, useAdvancedMarkerRef } from '@vis.gl/react-google-maps';

// 個別のマーカーコンポーネント(Refを扱うために分割が必要)
const CustomMarker = ({ position, title, description, isSelected, onClick, onClose }) => {
  const [markerRef, marker] = useAdvancedMarkerRef();
  return (
    <AdvancedMarker ref={markerRef} position={position} onClick={onClick}>
     <Pin background="#ea4335" />
     {isSelected && (
       <InfoWindow anchor={marker} onCloseClick={onClose}>
         <h3>{title}</h3>
         <p>{description}</p>
       </InfoWindow>
     )}
    </AdvancedMarker>
  );
 };

const App = () => {
  // どのマーカーのInfoWindowを開くかの状態管理
  const [selectedMarkerId, setSelectedMarkerId] = useState<string | null>(null);
 
  const centerPosition = { lat: 35.681236, lng: 139.767125 };
   
  const spots = [
    { id: '1', position: { lat: 35.681236, lng: 139.767125 }, title: '東京駅', desc: 'ハブ駅' },
    { id: '2', position: { lat: 35.68944, lng: 139.69167 }, title: '新宿駅', desc: '商業の中心'},
  ];
 
  return (
    <div style={{ height: '100vh', width: '100%' }}>
      <APIProvider apiKey="YOUR_API_KEY">
        <Map defaultZoom={13} defaultCenter={centerPosition} mapId="YOUR_MAP_ID">
   
          {/* 中心マーカー */}
          <AdvancedMarker position={centerPosition}>
            <Pin background="#4285F4" scale={1.5} />
          </AdvancedMarker>
   
          {/* 周辺マーカーのレンダリングループ */}
          {spots.map((spot) => (
            <CustomMarker
              key={spot.id}
              position={spot.position}
              title={spot.title}
              description={spot.desc}
              isSelected={selectedMarkerId === spot.id}
              onClick={() => setSelectedMarkerId(spot.id)}
              onClose={() => setSelectedMarkerId(null)}
            />
          ))}
        </Map>
      </APIProvider>
    </div>
  );
};
 
export default App;

After: react-easy-google-map を使った場合

面倒な useState APIProviderなどのラップ処理がなくなり、表示したいデータをPropsとして渡すだけで完結します!

import React from 'react';
import { GoogleMap } from 'react-easy-google-map';
   
const App = () => {
  // 中心のマーカー設定
  const centerMarker = {
    position: { lat: 35.681236, lng: 139.767125 },
    pinStyle: { backgroundColor: '#4285F4', scale: 1.5 },
  };
  
  // 周辺マーカーとInfoWindowの内容
  const data = [
    {
       id: '1',
       position: { lat: 35.681236, lng: 139.767125 },
       info: {
         headerContent: <h3>東京駅</h3>,
         bodyContent: <p>ハブ駅</p>,
       },
    },
    {
      id: '2',
      position: { lat: 35.68944, lng: 139.69167 },
      info: {
        headerContent: <h3>新宿駅</h3>,
        bodyContent: <p>商業の中心</p>,
      },
      pinStyle: { backgroundColor: '#ea4335' },
    },
  ];
  
  return (
    <div style={{ height: '100vh', width: '100%' }}>
      <GoogleMap
        apiKey="YOUR_API_KEY"
        mapId="YOUR_MAP_ID"
        centerMarker={centerMarker}
        data={data}
      />
    </div>
  );
};
 
export default App;

react-easy-google-map の特徴と使い方

導入は簡単!以下のコマンドを実行します。

npm install react-easy-google-map @vis.gl/react-google-maps

peerDependencies として @vis.gl/react-google-maps を要求するため、合わせてインストールします。

主な機能

  1. 直感的なピンのカスタマイズ:
    各データの pinStyleプロパティで、背景色(backgroundColor)や枠線色(borderColor)、サイズ(scale)を簡単に変更できます。
  2. InfoWindowの自動制御:
    info プロパティに headerContentbodyContent(JSXを渡せます!)を設定するだけで、クリック時のポップアップを自動で処理します。同時に開くのは1つだけになるよう内部で制御しています。
  3. 高度なカスタマイズのための拡張性も確保:
    単なる手抜きライブラリではなく、基礎となっている Map コンポーネントへの mapPropsや、InfoWindowへの infoWindowPropsを渡せる設計にしており、独自のスタイリングやズーム設定のオーバーライドも可能です。
  4. TypeScript完全対応:
    ジェネリクスを用いて開発しており、データ配列に独自のプロパティを含めても型落ちせず、快適な開発体験を提供します。

おわりに

「とりあえずマップを表示して、いくつかピンを立てて詳細を見せたい」というユースケースにおいて、react-easy-google-map は強力な時短ツールになるはずです。

もし「便利そうだな」と思っていただけたら、ぜひこのプロジェクトで使ってみてください。そして、GitHubリポジトリへの Star ⭐️ をいただけると、開発の大きなモチベーションになります!

バグ報告や「こんな機能が欲しい」といったIssue、Pull Requestも大歓迎です。最後まで読んでいただきありがとうございました!

コメント

タイトルとURLをコピーしました