react-map-gl について
FixMyBerlin / FMC プロジェクト向けに、`react-map-gl/maplibre` を使った MapLibre 開発とレビューの規約をまとめたスキルです。React のレイヤー、イベント、地図状態、テスト時の確認方法を扱います。
主な機能
- 01宣言的なソースとレイヤーのパターン
- 02地図イベントとアクセスの規約
- 03ロード状態のガードとデバッグ公開
- 04フィーチャー選択とハイライトのルール
- 05URL とビューポートの同期
活用シーン
- 01地図のソースやレイヤー変更のレビュー
- 02フィーチャーのクリックやホバー処理の実装
- 03地図表示と URL 状態の同期
- 04エージェントや E2E テストでの地図確認
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ fixmyberlin/ fixmyskills --skill react-map-glインストール後、Claude Code で/react-map-glを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
references/cursor-handling.mddeclarative-source-layer.mdfeature-state.mdflat-source-layer.mdinitial-view-state.mdinteractive-layer-ids.mdlayer-visibility-vs-unmount.mdmap-debug-exposure.mdmap-event-handlers.mdmap-images.mdmap-loaded-hook.mdmap-props-attribution-locale.mdmap-provider-wrapper.mdmap-url-state.md詳細
react-map-gl (MapLibre)
FixMyBerlin / FMC プロジェクトにおける react-map-gl/maplibre の規約です。react-map-gl 単体ではなく、react-map-gl/maplibre からインポートしてください。必ず maplibre-gl/dist/maplibre-gl.css をインポートしてください。
import 'maplibre-gl/dist/maplibre-gl.css'
import { MapProvider, Map, Source, Layer, useMap } from 'react-map-gl/maplibre'
ルール
| トピック | ルール |
|---|---|
| ソース/レイヤー | JSX 内では <Source> と <Layer> のみを使用します。アプリのデータに対して map.addSource / map.addLayer(または remove*)を呼び出してはいけません。layout.visibility または条件付きレンダーで表示/非表示を切り替えます。 |
| レイヤー構造 | フラットな兄弟要素にします。ソース ID ごとに <Source> を 1 つ置き、その後に <Layer> を兄弟要素として配置します(ネストしません)。 |
| マップイベント | カメラ、ポインター、読み込み、タイルのライフサイクルに関するイベントは、<Map> のコールバックプロパティに指定します。useEffect と map.on(…) の組み合わせは使いません。useEffect は、読み込み後の React → マップの同期、または Map のプロパティにないイベント(styleimagemissing)にのみ使用します。 |
| マップへのアクセス | アプリのマップ UI は <MapProvider> でラップします。useMap() は <Map id="…"> で指定した ID を使います。子コンポーネントからアクセスするために <Map> に ref を渡してはいけません。 |
| マップの準備完了 | useMapLoaded()(onLoad で設定)を使って、getStyle、queryRenderedFeatures、setFeatureState の呼び出し前に準備完了を確認します。 |
| デバッグ用の公開 | onLoad で exposeMainMapForDebugging(event.target) を呼び出します(開発環境と Playwright でのみ使用)。エージェント/テストは window.__mainMap を参照します。 |
| クリック | レイヤー ID は interactiveLayerIds に指定し、event.features を読み取ります。URL のフィーチャーを同期する場合を除き、主要なクリック対象の取得に queryRenderedFeatures を使ってはいけません。 |
| フィーチャーの強調表示 | インスペクター/フォームの状態は React を正とし、マップの色調変更には setFeatureState(paint)または React の filter レイヤーを使います。新しい状態を適用する前に、古い状態をクリアします。 |
| 帰属表示 | <Map> では attributionControl={false} を指定し、子要素として <AttributionControl compact> を配置します。すべての <Map> で RTLTextPlugin={false} を指定します。 |
| ビューポート URL | ズームに応じて丸めた zoom/lat/lng を使います。onMoveEnd で history: 'replace' を指定して書き込みます。 |
| ビュー状態 | URL を初期値とする非制御の initialViewState を使います。プログラムによるカメラ操作が必要な場合を除き、React でビュー状態をミラーリングしません。 |
読むファイル
自分のタスクに該当するファイルだけを読んでください。
| タスク | 読むファイル |
|---|---|
<Source> / <Layer> の追加またはレビュー、addSource の削除 | declarative-source-layer.md、flat-source-layer.md |
| レイヤーの表示/非表示 | layer-visibility-vs-unmount.md |
クリック/ホバーのハンドラー、<Map> のコールバックの選択 | map-event-handlers.md、interactive-layer-ids.md |
| フィーチャー上のカーソル | cursor-handling.md |
| 子コンポーネント/兄弟コンポーネントでマップインスタンスが必要な場合 | map-provider-wrapper.md |
読み込み前の getStyle / queryRenderedFeatures | map-loaded-hook.md |
| エージェント/E2E でのマップ検査 | map-debug-exposure.md |
選択/ホバーしたフィーチャーのハイライト、setFeatureState | feature-state.md |
| 初期カメラ、fitBounds、境界 | initial-view-state.md |
?map= URL の同期 | map-url-state.md |
| 帰属表示、ロケール、RTL テキストプラグイン | map-props-attribution-locale.md |
アイコンの欠落または動的アイコン、styleimagemissing、addImage | map-images.md |
すべてのファイルは references/ にあります。スキル tanstack-router-conventions(?map= の契約)、zustand-state-management(useMapLoaded ストア)、playwright-skill(E2E マップヘルパー)と組み合わせてください。
レビューチェックリスト
- アプリデータに対して
addSource/addLayer/removeSource/removeLayer/setLayoutPropertyを使用していないこと。フラットな<Source>+<Layer>を使用すること -
<MapProvider>を親に配置し、useMap()を使用すること。<Map>にrefを指定しないこと - 移動/クリック/ホバーに
useEffect+map.onを使用していないこと。ビューポートの同期にはonMoveEnd/onMoveを使用すること - マップを操作するエフェクトが React → map の同期であり、
mainMap+mapLoadedでガードされていること -
onLoadがマップ準備完了フラグを設定し、exposeMainMapForDebuggingを呼び出すこと - クリック可能なレイヤー ID がすべて
interactiveLayerIdsに含まれていること。ハンドラーではevent.featuresを使用すること - 新しいフィーチャーの状態を適用する前に、古いフィーチャーの状態がクリアされていること。フィーチャーに ID があること(ベクターでは
promoteId) -
attributionControl={false}+ 子の<AttributionControl>を使用すること。RTLTextPlugin={false}を指定すること - URL:共有の
parseMapParam/serializeMapParamを使用すること。パン/ズーム時はreplaceを使用し、シリアライズした値をencodeURIComponentで囲まないこと - 固定アイコンには
useMapImagesを使用すること。動的アイコンにはuseEffect内のstyleimagemissingを使用し、off()でクリーンアップし、hasImageでガードすること
コメント
Markdown 対応