In the previous post, React & Mapbox: A Map Made in Heaven, Part 1 we walked through creating a Mapbox account, creating a react application using the Facebook tool – create-react-app – and creating a simple App component. This post will walk through building out a Map component and importing it into the already existing App component.
Step 1 — Creating the Map Component
Install react-map-gl
, a wrapper for Mapbox GL that was created by Uber.
In Terminal, run the following code:
$ yarn add react-map-gl
Uber has provided some boilerplate code to get us started. Let’s break down the following lines. First, we need to import React methods and the Component class from the React library. Then, import React methods from the Mapbox library; we're going to be using the Popup and Marker methods.
Next, we instantiatiate the component we're creating. In this case, it’s called Map and it’s extending the React Component class. As you know, a React component can access dynamic information in two ways: props and state. Since a component is able to decide its own state, in order to make our Map component have state, we must give it a state property and declare it inside the constructor method.
import React, {Component} from 'react'; import ReactMapGL from 'react-map-gl'; class Map extends Component { state = { viewport: { width: 400, height: 400, latitude: 37.7577, longitude: -122.4376, zoom: 8 } }; render() { const { viewport } = this.state; return ( <ReactMapGL width={viewport.width} height={viewport.height} latitude={viewport.latitude} longitude={viewport.longitude} zoom={viewport.zoom} onViewportChange={(viewport) => this.setState({viewport})} /> ); } } export default Map;
The render
method is what renders the component to the browser, so it controls what is displayed for this component. From this function, we return what we want to display. In this case, we are rendering the Mapbox map component <ReactMapGL />
and including the viewport properties.
The onViewportChange
callback is fired when the user interacts with the map. User interaction and transition will not work without a valid one.
The export
exposes the Map class to other files. This means that other files can import from this file in order to use the Map class.
The current mapbox-gl release requires its stylesheet be included at all times. The marker, popup and navigation components in react-map-gl also need the stylesheet to work properly. Therefore, in the public/index.hmtl
file, add the Mapbox stylesheet to the head:
<!-- index.html --> <link href='https://api.tiles.mapbox.com/mapbox-gl-js/v0.42.0/mapbox-gl.css' rel='stylesheet' />
Step 2 —Complete the ReactMapGL Component
Use the following Github repo as a guide and set the Mapbox token variable in the index.js
.
const MAPBOX_TOKEN = '';
There are several ways to provide a token to your app. In this example, we're passing it as a prop to the ReactMapGL instance
Another recommended way is using the dotenv package and put your key in an untracked .env file, that will then expose it as a process.env variable, with much less leaking risks.
Put the API key in a .env file:
REACT_APP_MAPBOX_ACCESS_TOKEN='key in here'
Then, set the MAPBOX_TOKEN variable as follows:
const MAPBOX_TOKEN = process.env.REACT_APP_MAPBOX_ACCESS_TOKEN;
Interactive Map Properties
This component renders MapboxGL and provides full interactivity support. It is the default exported component from ReactMapGL and we need to set up the following properties on the map:
mapStyle: several basic templates are already provided by Mapbox here, but you can also design your own on their Studio Platform
viewport: you can specify latitude and longitude of the object that you want to define the center of your map, as well as how zoomed in on that object you want to be.
mapboxApiAccessToken: once again, it’s important to obtain your unique token to access the Mapbox API
render() { return ( <ReactMapGL mapStyle="mapbox://styles/mapbox/light-v9" onViewportChange={(viewport) => this.setState({viewport})} mapboxApiAccessToken={MAPBOX_TOKEN} /> ); }
Step 3 — Import the Map Component into the App Component
import Map from '../Map'; <div className="App"> <Map component={Map} /> </div>