Mapbox GL JS + React

見出し

これはレイアウト確認用のダミーテキストです。

MapboxでWebアプリケーションを構築する際、ReactMapbox GL JSをよく使用します。これらのライブラリは組み合わせて強力に機能するため、これら2つを接続するためのいくつかのテクニックを紹介したいと思います。

React の強みは、DOM の上に抽象化レイヤーを設けている点にあります。コンポーネントが render() を呼び出す際にユーザーに表示される内容は内部で適切に管理され、実装者はインターフェースの動作など、より高度なタスクに取り組むことができます。

Reactと、DOMを操作し状態を管理する他のライブラリ(Mapbox GL JSなど)との連携は混乱を招きやすいでしょう。両者の間で効果的に通信するにはどうすればよいでしょうか?この混乱を解消するために、抽象化レイヤーを提供するコンポーネントラッパーを利用するのが一般的です。この手法は、アプリケーション全体でpropsとして渡される標準化されたルールを適用するのに効果的です。例としては、モーダルコンポーネントがあります。ラッパーは、サイズやタイトルなどのカスタマイズを可能にし、常に同じであるべき技術的な詳細(キーバインディングのイベント処理やアクセシビリティ)は、下位レベルのモーダルコンポーネントに隠されています。

import Modal from "some-react-modal"

export class CoolModal extends React.Component {
    render() {
        const { title, size, onExit, children } = this.props;
        const width = size === 'small' ? '360px' : '600px';
        return (
            <Modal
                onExit={onExit}
                enableKeys={true}
                closeOnOutsideClick={true}>
                <div style={{width}}>
                    <h1>{title}</h1>
                    {children}
                </div>
            </Modal>
        );
    }
}

So it’s natural to look for a <Mapbox /> component within the React ecosystem (see react-map-gl or react-mapbox-gl as example). The goals however of a Modal component are small and applying this same technique to a feature rich library is a high tradeoff. If you are missing functionality, it’s up to the maintainer to expand support through additional props.

ありがたいことに、Mapbox GL JSはラッパー抽象化なしでうまく機能します。サードパーティライブラリがReactと連携して動作するのは非常に簡単です!

マップを初期化するためのエントリポイントは、render関数のreturnステートメントで提供される単一の要素を介します。簡単な例を次に示します。

class Map extends React.Component {
    componentDidMount() {
        this.map = new mapboxgl.Map({
            container: this.mapContainer,
            style: 'mapbox://styles/mapbox/streets-v9'
        });
    }

    componentWillUnmount() {
        this.map.remove();
    }

    render() {
        const style = {
            position: 'absolute',
            top: 0,
            bottom: 0,
            width: '100%'
        };

        return <div style={style} ref={el => this.mapContainer = el} />;
    }
}

ReactDOM.render(<Map />, document.getElementById('app'));

JSXはdivコンテナを作成し、マップはライフサイクルメソッドを通じて継続的に更新されます。重要なのはref属性です。マップはcomponentDidMount内で初期化され、そのコンテナ値はthis.mapContainerの代入として設定されます。これは、DOMノードへの直接アクセスを提供するReactの方法です。

さらに詳細な例を見てみましょう。

基本的な例

この例では、Reactは位置データを状態として地図に渡します。その状態は、moveイベントをリッスンし、地図の外側のコンテナがそれらの値を表示することによって更新されます。これは、より上位のコンポーネントから渡されるプロップデータである可能性もありますが、アプリ全体を1つのコンポーネントとして含めるために、状態を使用しました。

リアクティブなツールチップの例

注目すべき詳細は以下のとおりです。

  • ベクタータイルにあるデータは、queryRenderedFeaturesを使用してマウスカーソルの下で収集されます
  • mapboxgl.Marker インスタンスは、地図上に収集されたデータを表示するために使用されます(Mapbox GL JS が地図上の位置を制御します)が、マーカーの内容は ReactDOM.render を使用して React で動作します。

このような地図データの取得は、Mapboxからのタイルに限定されません。addSourceを使用して追加するデータレイヤーにも、同じ手法を適用できます。これは、大量のデータを保存し、必要に応じてリクエストするための強力な方法です。

データオーバーレイの例

ここでは、GeoJSONがアプリによって提供され、ソースとして地図に追加されます。クリックハンドラーは、componentDidUpdateが呼び出されたときに地図が応答するデータの再スタイリング方法を指示します。

多数のコンポーネントが同じデータの状態を知る必要があるより複雑なアプリケーションでは、Reduxを使用します。Reduxを使用したこの例のバージョンを提供しました。これは、Studioと同様のアーキテクチャをモデル化しています。Mapbox StudioでのReduxの使用方法の詳細については、大規模なWebアプリでの状態管理のためのReduxDavid Clark著)をご覧ください。

これが、Reactと並行してMapbox GL JSを使用するための入門書として役立ち、Mapboxでいくつかの異なる概念をどのように実現しているかの背景情報を提供できれば幸いです。これらのデモの改善を提案したり、詳細を知りたい場合は、https://github.com/mapbox/mapbox-react-examples/をご覧ください。

さらに詳しく知りたい方は、Tom MacWrightによるリアクティブアプリケーションにおけるMapbox GL JSに関する記事をご覧ください。彼は、スタイルアップデートを迅速に適用するために、ReactのレンダリングコンセプトをMapbox GL JSに直接適用した方法を説明しています。もしこの内容にご興味をお持ちでしたら、当社のエンジニアリング部門の求人情報をご覧ください。採用中です!

これはレイアウト確認用のダミーテキストです。

これはレイアウト確認用のダミーテキストです。

関連記事