Next.jsで、Mapboxによる地図を表示するにはどうすればよいか、試行錯誤していましたが、 やっと地図が表示できたので、やり方を纏めておきます。
Mapboxは、Web、モバイル、ARなどさまざまなプラットフォームで使える地図サービスです。
公式サイト では、
Mapbox is the location data platform for mobile and web applications. We provide building blocks to add location features like maps, search, and navigation into any experience you create.
と説明されています。
ここでは、Next.jsのアプリケーションに、Mapboxを使って地図を表示する方法を書いてみます。
(TypeScriptは使っていません(^^; )
Mapboxを使うには、アカウントを作成し、アクセストークンを取得する必要があります。 詳細は割愛します。
MapboxをReactで使うためのらいぶらりとして、react-map-glというのがありました。これを試してみたところ、Mapboxのオプションで trackResize
というオプションがあるのですが、これがfalse
に固定されていることが不満で使うのをやめました。
trackResize
オプションは、MapboxのAPI Referrenceで、
If true , the map will automatically resize when the browser window resizes.
と説明されています。つまり、react-map-gl
を使った場合、Windowのリサイズに地図が自動で追従してリサイズされません。(どうにかすればリサイズできるのでしょうけど... 今の僕にはそんなスキルはありませんでした...)
Mapboxが提供するnpmパッケージを使用します。
npm install --save mapbox-gl
でインストールします。
Mapboxによる地図を表示するだけの単純なコンポーネントを作ります。
components/map.js
としました。
結論を言うと、↓のようなコードになりました。
import React from 'react';
import mapboxgl from 'mapbox-gl';
mapboxgl.accessToken = process.env.MAPBOX_TOKEN;
class Map extends React.Component {
options = {
container: 'map',
style: 'mapbox://styles/mapbox/dark-v10',
center: [137.6850225, 38.258595],
zoom: 5
};
constructor(props) {
super(props);
}
componentDidMount() {
this.map = new mapboxgl.Map(this.options);
}
render() {
return(
<div id="map">
<div ref={el => this.mapContainer = el} />
</div>
)
}
}
export default Map;
日本のおおよその中心を地図の中心として、表示するようにしています。
Mapboxのアクセストークンは、環境変数として定義しています。
ハマった点は、options.container
に何を指定すればよいか全くわからず、長いこと悩みましたが、
結局地図を埋める要素の親の要素のid
を指定することで解決しました。(上の例では、map
を指定しました。)
地図用コンポーネントができたら、早速ページにコンポーネントを適用してみます。 ここの実装については、
Making Next.js and Mapbox GL JS get along
に助けられました。
この記事によると、
Without diving into great detail, Mapbox GL JS uses the global window object under the hood. When rendering components server-side as we want to do using next.js, this object does not exist.
とあり、つまり、MapboxのJSが必要とするグローバルなwindowオブジェクトが、Next.jsによるSSR時は存在しない(ので、そのままでは使えない)ということのようです。これを回避するために、Next.jsが提供するnext/dynamic
というパッケージを使い、地図を表示します。
結果、ページ(pages/index.js)は↓のような実装となりました。
import dynamic from 'next/dynamic';
import '../styles/styles.scss';
const Map = dynamic(() => import('../components/map'), {
loading: () => <p>Loading...</p>,
ssr: false
});
export default function Index() {
return (
<div id="app">
<Map />
</div>
);
}
これで、無事に地図が表示できるようになりました。
もともと、Next.js + TypeScript + Mapboxで何か作ろうと思っていたのですが、なかなかうまく行かず、右往左往しまいして、一旦TypeScriptを諦めて、なんとかここまで来ました。 おそらく、TypeScript環境下でも地図は表示できるんじゃないかと思えてきました。 もし、内容におかしな点があれば、Twitterなどで指摘頂けるとありがたいです!