React + Mapbox GeoJSON Example

May 4, 2020 | Programming

Here’s an example of how to create a Mapbox map in React using a GeoJSON data set. When I started building my first React Mapbox map I built them around some of the other pre-built components out there like ReactMapboxGL or react-map-gl. Both of these wrappers are great but eventually figured out I was better able to control all the Mapbox features on my own by targeting the Mapbox GL JS libary directly vs using a another component.

This example uses React hooks but could easily be updated for a class component if that is what you are working with. Below is one component called Districts that loads Minnesota’s eight congressional districts from a separate geojson file. After loading the districts they are given a unique fill-color and added as a layer.

You can view the entire React Mapbox GeoJSON example project in the GitHub repository or you can view a live example at clintmcmahon.github.io/react-mapbox-example

Districts.js React Component

import React, { useState, useEffect, useRef } from "react";import mnDistricts from "./data/mn/mn-districts.geojson";import ReactDOM from 'react-dom';import mapboxgl from 'mapbox-gl';function Districts(props) {    mapboxgl.accessToken = process.env.REACT_APP_MAPBOX_KEY;    const mapContainer = useRef(null);    const [long, setLong] = useState(-94.503809);    const [lat, setLat] = useState(46.443226);    const [zoom, setZoom] = useState(4.5);    const [hoveredDistrict, _setHoveredDistrict] = useState(null);    const hoveredDistrictRef = useRef(hoveredDistrict);    const setHoveredDistrict = data => {        hoveredDistrictRef.current = data;        _setHoveredDistrict(data);    };    useEffect(() => {        let map = new mapboxgl.Map({            container: mapContainer.current,            style: "mapbox://styles/mapbox/light-v10",            center: [long, lat],            zoom: zoom        });            // Add zoom and rotation controls to the map.            map.addControl(new mapboxgl.NavigationControl());        map.once("load", function () {            map.addSource('district-source', {                'type': 'geojson',                'data': mnDistricts            });            map.addLayer({                'id': 'district-layer',                'type': 'fill',                'source': 'district-source',                'layout': {},                'paint': {                    'fill-color': [                        'match',                        ['get', 'CD116FP'],                        '01',                        '#5AA5D7',                        '02',                        '#02735E',                        '03',                        '#00E0EF',                        '04',                        '#84D0D9',                        '05',                        '#202359',                        '06',                        '#CE7529',                        '07',                        '#00AE6C',                        '08',                        '#0056A3',                        /* other */ '#ffffff'                    ],                    'fill-opacity': [                        'case',                        ['boolean', ['feature-state', 'hover'], false],                        .8,                        0.5                    ]                }            });            map.on('mousemove', 'district-layer', function (e) {                if (e.features.length > 0) {                    if (hoveredDistrictRef.current && hoveredDistrictRef.current > -1) {                        map.setFeatureState(                            { source: 'district-source', id: hoveredDistrictRef.current },                            { hover: false }                        );                    }                    let _hoveredDistrict = e.features[0].id;                    map.setFeatureState(                        { source: 'district-source', id: _hoveredDistrict },                        { hover: true }                    );                    setHoveredDistrict(_hoveredDistrict);                }            });            // When the mouse leaves the state-fill layer, update the feature state of the            // previously hovered feature.            map.on('mouseleave', 'district-layer', function () {                if (hoveredDistrictRef.current) {                    map.setFeatureState(                        { source: 'district-source', id: hoveredDistrictRef.current },                        { hover: false }                    );                }                setHoveredDistrict(null);            });        });    }, []);    return (        <div className="district-map-wrapper">            <div id="districtDetailMap" className="map">                <div style={{ height: "100%" }} ref={mapContainer}>                </div>            </div>        </div>    );}export default Districts;

Minnesota Congressional Districts GeoJSON

This geojson data set represents Minnesota’s eight congressional districts that I pulled from the US Census. Each feature has a property “CD116FP” that I’m using to set the fill-color of each district layer. The GeoJSON data is so big I didn’t include it in this blog post but you can download it from the Github repo.

You can view the source on Github.

That’s it. Happy coding!

0 Comments

Submit a Comment

Your email address will not be published. Required fields are marked *