ReactでReact-Leafletをインストールしてもうまく動かなかった際の解決方法

  •  
 
トビウオ に投稿
概要

こちらもおおよそタイトル通りです。
React流の文法でLeaflet.jsを扱えるReact-Leafletというのがあるのですが、それを「yarn add react-leflet leaflet」などとしてインストールしても「動かない」(地図がちゃんと表示されない、マーカーが表示されない)といったトラブルが発生することがあります。
ググれば解決策は出てくるのですが、無駄にややこしくて忘れてしまうのでメモしておきます。

地図が表示されない問題の対策
import { Map, TileLayer } from 'react-leaflet';

return (
  <Map center={[35.710063, 139.8107]} zoom={16}>
    <TileLayer attribution='&amp;copy <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
      url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png" />
  </Map>
);

これで動かないのを見た時は バグかと思いました が、次のようにCSSをあてがい、heightを強制的に指定してやるとなぜか動きます。

import "leaflet/dist/leaflet.css";
import { Map, TileLayer } from 'react-leaflet';

return (
  <Map center={[35.710063, 139.8107]} zoom={16} style={{ height: '100vh' }}>
    <TileLayer attribution='&amp;copy <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
      url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png" />
  </Map>
);

参考資料:reactjs - Bug display with react leaflet - Stack Overflow

マーカーが表示されない問題の対策
import "leaflet/dist/leaflet.css";
import { Map, TileLayer, Marker, Popup } from 'react-leaflet';

return (
  <Map center={[35.710063, 139.8107]} zoom={16} style={{ height: '100vh' }}>
    <TileLayer attribution='&amp;copy <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
      url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png" />
    <Marker position={[35.710063, 139.8107]} >
      <Popup>東京スカイツリー</Popup>
    </Marker>
  </Map>
);

なんでこれで動かへんねん。というわけで散々ググった結果、「既存のアイコンの状態を上書きする」JavaScriptを書くといいと出ました。つまり、次のような行を冒頭に追加すればいいのです。

import Leaflet from 'leaflet';

delete Leaflet.Icon.Default.prototype._getIconUrl;
Leaflet.Icon.Default.mergeOptions({
  iconRetinaUrl: require('leaflet/dist/images/marker-icon-2x.png'),
  iconUrl: require('leaflet/dist/images/marker-icon.png'),
  shadowUrl: require('leaflet/dist/images/marker-shadow.png'),
});

ただ、そのままコピペしてもまだ問題が発生します。
まず、@types/leafletを導入しているのに「Property '_getIconUrl' does not exist on type 'Default'. TS2339」と出て実行できません。
そこで、anyにキャストして強引にメソッドを参照するというテクニックが必要になります。

また、ESLint的には「アンダースコアを含むメソッド名」「グローバル空間のrequire」が気になるらしく、チェックによりエラーを出してきます。
そのため、コードブロック全体を「/* eslint-disable */」で囲うなどの小細工が必要になります。

import Leaflet from 'leaflet';

/* eslint-disable */
delete (Leaflet.Icon.Default.prototype as any)._getIconUrl;
Leaflet.Icon.Default.mergeOptions({
  iconRetinaUrl: require('leaflet/dist/images/marker-icon-2x.png'),
  iconUrl: require('leaflet/dist/images/marker-icon.png'),
  shadowUrl: require('leaflet/dist/images/marker-shadow.png'),
});
/* eslint-disable */

参考資料:javascript - react-leaflet map not correctly displayed - Stack Overflow

コメントを追加

プレーンテキスト

  • HTMLタグは利用できません。
  • 行と段落は自動的に折り返されます。
  • ウェブページのアドレスとメールアドレスは自動的にリンクに変換されます。
CAPTCHA
この質問はあなたが人間の訪問者であるかどうかをテストし、自動化されたスパム送信を防ぐためのものです。