全てのドキュメントchevron-rightヘルプchevron-rightarrow-leftチュートリアルchevron-rightReactアプリでMapbox GL JSを使う

ReactアプリでMapbox GL JSを使う

Reactは、ユーザーインターフェースの構築に使われるポピュラーなJavaScriptライブラリです。ReactはDOMを操作するため、同じくDOMを操作して状態を管理する他のライブラリ(Mapbox GL JSなど)と連携させると、混乱してしまうことがあります。

このチュートリアルでは Mapbox GL JS を使用して地図をレンダリングし、地図の中心点の座標とそのズームレベルを表示し、ユーザーが地図を操作したときに表示される地図を更新する React ウェブアプリの作成方法を学びます。このチュートリアルで説明されている基本を使用するとReact と Mapbox GL JS の両方を使用する、より複雑なアプリを作成できるようになります。このチュートリアルでは React HooksとClass Componentsのコードを紹介しています。

はじめに

  • Mapboxアクセストークン あなたのMapboxアクセストークンはアカウントページで確認できます。
  • Mapbox GL JS Mapbox GL JSは、ウェブマップの構築に使用されるJavaScriptライブラリです。
  • テキストエディタ HTML、CSS、JavaScriptの記述には、お好みのテキストエディタをお使いください。
  • Node.js and npm Reactアプリをローカルで実行するために必要なコマンドを実行するには、Node.js and npmをインストールしてください。
  • Reactに精通していること このチュートリアルを完了するためにReactの使用経験は必要ありませんが、基本的なコンセプトとワークフローに精通している必要があります。

Reactのアプリ構造を設定する

まずは、use-mapbox-gl-js-with-reactという新しいフォルダを作成します。

use-mapbox-gl-js-with-reactフォルダの中に、新しいファイルを作成します。

  • package.json - このファイルは、ReactとMapbox GL JSを含む、アプリが必要とするすべてのNodeパッケージを指定するために使用します。

use-mapbox-gl-js-with-reactフォルダの配下に、publicというフォルダを作成します。public`というフォルダの中に、1つのファイルを作成します。

  • index.html - このHTMLファイルは、ユーザーが対話的な操作ができるようにレンダリングされたMapboxの地図を表示します。

use-mapbox-gl-js-with-react フォルダの配下に、src という名前の別のフォルダを作成します。このsrcフォルダの中に、3つのファイルを作成します。

  • App.js - このJavaScriptファイルはReactアプリをセットアップします。
  • index.css - このCSSファイルは、マップとサイドバーを正しくフォーマットするためのスタイルを含みます。
  • index.js - このJavaScriptファイルは、Reactアプリを設定します。index.js: このJavaScriptファイルは、Mapboxのマップをブラウザにレンダリングします。

これらのフォルダとファイルを作成すると、以下のようなファイル構成になります。

folder use-mapbox-gl-js-with-react
code package.json
folder public
code index.html
folder src
code App.js
code index.css
code index.js

以下のコードを package.json にコピーしてください。

package.json
{
"name": "use-mapbox-gl-js-with-react",
"version": "0.1.0",
"private": true,
"dependencies": {
"mapbox-gl": "^2.14.1",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-scripts": "^4.0.3"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build"
},
"eslintConfig": {
"extends": [
"react-app"
]
},
"browserslist": [
"defaults",
"not ie 11"
],
"author": "Mapbox",
"license": "MIT"
}

このファイルには、React固有のNodeパッケージであるreactreact-domに加えて、アプリをビルドするためのCreate React Appとしても知られるreact-scriptsと、Mapbox GL JSにアクセスするためのmapbox-glが必要です。

変更を保存してください。

コマンドラインで、作成した use-mapbox-gl-js-with-react フォルダに移動します。このフォルダの中で、npm installというコマンドを実行すると、package.jsonファイルで指定したすべてのNodeパッケージがインストールされます。このステップでは、package-lock.jsonファイルも作成されます。

HTMLページの作成

public/index.htmlファイルを開き、以下のコードをコピーアンドペーストします。

public/index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta
name="description"
content="Create a React web app that uses Mapbox GL JS to render a map"
/>
<title>Use Mapbox GL JS in a React app</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
</body>
</html>

このコードは、ユーザーが目にするHTMLページの構造を作成します。ページの <body> 内には、ID root を持つ <div> 要素があります。この<div>は、Reactアプリがページ上でレンダリングされるためのコンテナです。

変更を保存してください。

Reactアプリの作成

src/index.jsファイルを開きます。以下を追加して、2つのスタイルシートと、これから構築するMapbox GL JSマップをインポートします。

src/index.js
import React from 'react';
import ReactDOM from 'react-dom';
import 'mapbox-gl/dist/mapbox-gl.css';
import './index.css';
import App from './App';
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById('root')
);

最初のスタイルシートには、地図を表示するためのMapbox GL JSのスタイルが含まれています。2つ目のスタイルシートは、先ほど作成したindex.cssファイルで、ここにアプリ固有のCSSを追加していきます。

Mapbox GL JSの追加

src/App.js ファイルを開きます。以下のimport文をファイルの先頭に追加します。

src/App.js
import React, { useRef, useEffect, useState } from 'react';

次に、Mapbox GLをインポートし、アクセストークンを追加します。Mapbox GLをCreate React Appで使用するには、exclude mapbox-gl from transpilationに感嘆符(!)を追加し、eslintルールimport/no-webpack-loader-syntaxを無効にする必要があります。mapboxgl accessToken プロパティ に Mapbox アクセストークンの値を設定します。

src/App.js
import mapboxgl from '!mapbox-gl'; // eslint-disable-line import/no-webpack-loader-syntax
import MapboxLanguage from '@mapbox/mapbox-gl-language'; // eslint-disable-line import/no-extraneous-dependencies

これでReactアプリの設定ができました! 次のいくつかのステップでコードを追加する構造を作るために、App.jsの下部に以下を追加します。

src/App.js
</div>

変更を保存してください。

アプリのデフォルト状態の設定

次に、地図の初期の緯度、経度、ズームに使用するアプリのデフォルト値をいくつか設定します。Appの中に以下を追加します。

src/App.js
export default function App() {
const mapContainer = useRef(null);
const map = useRef(null);
const [lng, setLng] = useState(139.4534);
const [lat, setLat] = useState(35.4548);

この state には、マップの経度、緯度、ズームが格納されます。これらの値はすべて、ユーザーがマップを操作することによって変化します。

次に、マップを初期化します。以下のコードは、HTMLページのDOMツリーにアプリが挿入された直後に呼び出されます。

src/App.js
useEffect(() => {
if (map.current) return; // initialize map only once
map.current = new mapboxgl.Map({
container: mapContainer.current,
style: 'mapbox://styles/mapbox/streets-v11',
center: [lng, lat],
zoom: zoom
});

Mapboxの地図は、ReactのEffect hookや、クラスを使用している場合はcomponentDidMount()のライフサイクルメソッド内で初期化されます。ここで地図を初期化すると、Reactが地図を含む要素を作成する前に、Mapbox GL JSによる地図のレンダリングを開始しないようになります。また、地図の初期化の中で以下のオプションを設定します。

  • containerオプションは、Mapbox GL JSに特定のDOM要素の中で地図をレンダリングするように指定します。ここでアプリが mapContainer useRef または、クラスコンポーネントを使用している場合は refを受け取ることを想定しています。このチュートリアルの後半では、マップコンテナとして機能する HTML 要素に ref を割り当てます。
  • styleオプションは、地図が使用するスタイルを定義します (mapbox://styles/mapbox/streets-v11)。
  • centerzoom オプションは、ステートに格納されている lng, lat, zoom の値を使って、地図の中心座標とズームレベルを設定します。
  • フックを使用している場合は、地図の初期化状態を保存するために、mapuseRefも作成しました。この ref は、ユーザーが地図を操作したときに、地図が再ロードされないようにします。

変更を保存してください。

地図のレンダリング

次に、アプリ内で地図をレンダリングする必要があります。ReactアプリでMapboxの地図を初期化するためのエントリーポイントは、return文で提供される要素のひとつです。以下のコードをアプリの App の閉じた中括弧の上に追加してください。

src/App.js
setZoom(map.current.getZoom().toFixed(2));
});
<div>
<div className="sidebar">
Longitude: {lng} | Latitude: {lat} | Zoom: {zoom}

mapContainerref は、App を新しい <div> 要素で HTML ページに描画するよう指定しています。

マップが正しく表示されるためには、いくつかのスタイリングルールが必要です。以下のコードを index.css ファイルに追加してください。

.map-container {
height: 400px;
}

変更内容を保存します。コマンドラインで、npm startというコマンドを実行します。これにより、ローカルサーバーが起動し、新しいMapboxマップを含む新しいページがブラウザで開かれます。

ブラウザの開発者コンソールを開くと、「no-unused-vars」という警告が表示される場合があります。これらの変数は次のステップで使用しますのでご安心ください。

新しい座標の保存

次に、ユーザーが地図を操作したときに得られる新しい緯度、経度、ズームを保存する関数を作成する必要があります。Mapbox GL JS map.on('move')関数を記述して、ユーザーが地図を操作したときに、ステートをこれらの新しい値に設定します。フックを使用している場合は、追加の useEffect を作成し、以下のコードを追加します。クラスを使用している場合は、componentDidMount()の中に以下のコードを追加します。

src/App.js
const language = new MapboxLanguage();
map.addControl(language);
});
useEffect(() => {
if (!map.current) return; // wait for map to initialize
map.current.on('move', () => {
setLng(map.current.getCenter().lng.toFixed(4));

この関数は、フックを使用している場合は useState()、クラスを使用している場合は setState()を使用して、マップが移動したときに lng, lat, zoom の値をリセットします。また、以下のメソッドも使用しています。

  • getCenter() - Mapbox GLのJSメソッドで、地図の中心にあるポイントの新しい経度と緯度を取得します。
  • getZoom() - Mapbox GL JS メソッド, 地図に設定されているズームレベルを決定します。
  • toFixed() - JavaScriptのメソッドで、結果として得られる浮動小数点数を指定された桁数に切り上げるためのものです。

座標の表示

この情報を収集して保存することができたので、returnを使って地図上に表示することができます。地図を格納するために作成した <div> の開始タグの中に、地図の経度、緯度、ズームを表示するための新しい <div> を追加します。これでreturn文は次のようになります。

src/App.js
setZoom(map.current.getZoom().toFixed(2));
});
});
return (
<div>
<div className="sidebar">
Longitude: {lng} | Latitude: {lat} | Zoom: {zoom}

サイドバーがページに正しく表示されるためには、いくつかのスタイリングルールが必要です。以下のCSSを index.css ファイルに追加してください。

.sidebar {
background-color: rgba(35, 55, 75, 0.9);
color: #fff;
padding: 6px 12px;
font-family: monospace;
z-index: 1;
position: absolute;
top: 0;
left: 0;
margin: 12px;
border-radius: 4px;
}

作業内容を保存して、ブラウザのページに戻ります。現在、地図の左上隅にはサイドバーがあり、index.cssで設定したCSSルールに従ってスタイルが設定されています。このサイドバーには、地図の中心の現在の緯度・経度と、ズームレベルが表示されます。これで、地図をズームしたりパンしたりすると、サイドバーの内容が更新されます。

完成プロダクト

Mapbox GL JSを使用して、地図をレンダリングし、地図の中心座標とズームレベルを表示し、ユーザーが地図を操作したときにその表示を更新するReactアプリを作成しました。

最終的な index.html ページは以下のようになります。

public/index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta
name="description"
content="Create a React web app that uses Mapbox GL JS to render a map"
/>
<title>Use Mapbox GL JS in a React app</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
</body>
</html>

最終的な index.js ファイルは以下のようになります。

src/index.js
import React from 'react';
import ReactDOM from 'react-dom';
import 'mapbox-gl/dist/mapbox-gl.css';
import './index.css';
import App from './App';
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById('root')
);

最終的な App.js ファイルは以下のようになります。

src/App.js
import React, { useRef, useEffect, useState } from 'react';
import mapboxgl from '!mapbox-gl'; // eslint-disable-line import/no-webpack-loader-syntax
import MapboxLanguage from '@mapbox/mapbox-gl-language'; // eslint-disable-line import/no-extraneous-dependencies
mapboxgl.accessToken = 'YOUR_MAPBOX_ACCESS_TOKEN';
export default function App() {
const mapContainer = useRef(null);
const map = useRef(null);
const [lng, setLng] = useState(139.4534);
const [lat, setLat] = useState(35.4548);
const [zoom, setZoom] = useState(9);
useEffect(() => {
if (map.current) return; // initialize map only once
map.current = new mapboxgl.Map({
container: mapContainer.current,
style: 'mapbox://styles/mapbox/streets-v11',
center: [lng, lat],
zoom: zoom
});
const language = new MapboxLanguage();
map.addControl(language);
});
useEffect(() => {
if (!map.current) return; // wait for map to initialize
map.current.on('move', () => {
setLng(map.current.getCenter().lng.toFixed(4));
setLat(map.current.getCenter().lat.toFixed(4));
setZoom(map.current.getZoom().toFixed(2));
});
});
return (
<div>
<div className="sidebar">
Longitude: {lng} | Latitude: {lat} | Zoom: {zoom}
</div>
<div ref={mapContainer} className="map-container" />
</div>
);
}

最終的な index.css ファイルは以下のようになります。

src/index.css
.map-container {
height: 400px;
}
.sidebar {
background-color: rgba(35, 55, 75, 0.9);
color: #fff;
padding: 6px 12px;
font-family: monospace;
z-index: 1;
position: absolute;
top: 0;
left: 0;
margin: 12px;
border-radius: 4px;
}

次のステップ

ここではMapbox GL JSを使用したReactアプリを作成しました。Mapbox React examples GitHub repositoryでより複雑なサンプルを参照することができます。