Tutorials
intermediate
JavaScript

Use Mapbox GL JS in a React app

Prerequisite

Familiarity with React and front-end development concepts.

React is a popular JavaScript library used for building user interfaces. Since React manipulates the DOM, it can be confusing to connect React with other libraries that also manipulate the DOM and manage state — like Mapbox GL JS. In this tutorial, you will learn how to create a React web app that uses Mapbox GL JS to render a map, display the coordinates of the map center point and its zoom level, then update the display when a user interacts with the map. You will be able to use the principles discussed in this tutorial to create more complex apps that use both React and Mapbox GL JS.

Getting started

  • A Mapbox access token. Your Mapbox access tokens are on your Account page.
  • Mapbox GL JS. Mapbox GL JS is a JavaScript library used for building web maps.
  • A text editor. Use the text editor of your choice for writing HTML, CSS, and JavaScript.
  • Node.js and npm. To run the commands necessary to run your React app locally, install Node.js and npm.
  • Working familiarity with React. You don't need to have a lot of experience using React to complete this tutorial, but you should be familiar with the underlying concepts and workflows.

Set up the React app structure

To get started, create a new folder called mapboxAndReact.

In the mapboxAndReact folder, create a new file:

  • package.json: This file is used to specify all of the Node packages that your app requires, including React and Mapbox GL JS.

In the mapboxAndReact folder, create a folder called public. In the public folder, create two new files:

  • index.html: This HTML file will display the rendered Mapbox map that your users will be able to interact with.
  • site.css: This file will contain the CSS necessary to format the map and sidebar correctly.

In the mapboxAndReact folder, create another folder called src. In the src folder, create a new file:

  • index.js: This JavaScript file will hold all of the React logic necessary to set and manage the app state and render the Mapbox map to the browser.

Once you have created these folders and files, you will have the following file structure:

mapboxAndReact
package.json
public
index.html
site.css
src
index.js

Copy the following code into package.json:

package.json
{
"name": "mapboxAndReact",
"version": "0.0.1",
"dependencies": {
"react": "^16.9.0",
"react-dom": "^16.9.0",
"react-scripts": "^3.1.1",
"mapbox-gl": "^1.3.1"
},
"scripts": {
"start": "react-scripts start"
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
}
}

In addition to the React-specific Node packages react, react-dom, and react-scripts, the package.json file also requires the mapbox-gl Node package. This package gives you access to the Mapbox GL JS JavaScript library.

Save your changes.

In the command line, navigate into the mapboxAndReact folder you created. In that folder, run the command npm install, which will install all the Node packages that you specified in the package.json file. This step also creates the package-lock.json file.

Create the HTML page

Open the index.html file and paste the following code into it:

index.html
<!DOCTYPE html>
<html lang='en'>
<head>
<title>Mapbox GL JS and React</title>
<meta charset='utf-8'>
<meta name='viewport' content='width=device-width, initial-scale=1'>
<link href='https://api.tiles.mapbox.com/mapbox-gl-js/v1.6.0/mapbox-gl.css' rel='stylesheet' />
<link href='site.css' rel='stylesheet'/>
</head>
<body>
<div id='app'></div>
</body>
</html>

This code creates the structure of the HTML page your users will see. There is a <div> element with the ID app in the <body> of the page. This <div> is the container in which the React app will be rendered on the page.

This code also links to two different stylesheets in the <head>. The first stylesheet is the Mapbox GL JS stylesheet, which ensures that the elements in your map are displayed correctly. The second stylesheet is the site.css file that you created earlier, which is where you will add your app-specific CSS.

Save your changes.

Create the React app

Open the index.js file. Add the following import statements to the top of the file:

index.js
import React from 'react';
import ReactDOM from 'react-dom';
import mapboxgl from 'mapbox-gl';

Next, set mapboxgl's accessToken property to the value of your Mapbox access token:

mapboxgl.accessToken = 'YOUR_MAPBOX_ACCESS_TOKEN';

Replace the MAPBOX_ACCESS_TOKEN placeholder with your Mapbox access token.

Now you can set up the React app! To create the structure that you will add the code from the next few steps in, add the following class declaration to the bottom of index.js:

class Application extends React.Component {
// Code from the next few steps will go here
}
ReactDOM.render(<Application />, document.getElementById('app'));

This defines a new component, Application, then specifies that it should be rendered in the <div> with the ID of app.

Save your changes.

Set the app's default state

Next, you will create some defaults for your app to use for the initial latitude, longitude, and zoom of the map. Add the following constructor inside the Application class you set up in the previous step:

index.js
constructor(props) {
super(props);
this.state = {
lng: 5,
lat: 34,
zoom: 2
};
}

The this.state object stores the original longitude, latitude, and zoom for the map. These values will all change as your user interacts with the map.

Above the closing curly brace of the class declaration, add a componentDidMount() function, which will be invoked right after the app is inserted into the DOM tree of your HTML page.

componentDidMount() {
const map = new mapboxgl.Map({
container: this.mapContainer,
style: 'mapbox://styles/mapbox/streets-v11',
center: [this.state.lng, this.state.lat],
zoom: this.state.zoom
});
}

The Mapbox map is initialized within React's componentDidMount() lifecycle method. Initializing your map here ensures that Mapbox GL JS will not try to render a map before React creates the element that contains the map. The following options are set inside the map initialization:

  • The container option tells Mapbox GL JS to render the map inside a specific DOM element. Here, the app expects to receive a mapContainer ref. Later in this tutorial, you will set the ref that is being referenced here.
  • The style option defines the style that the map will use (mapbox://styles/mapbox/streets-v11).
  • The center and zoom options set the center coordinates and zoom level of the map using the values of lng, lat, and zoom that are stored in state.

Save your changes.

Render the map

Now you need to render the map in your app. The entry point to initialize a Mapbox map in a React app is through a single element provided in the return statement of the render method. Add the following code to your app above the closing curly brace of the class declaration:

index.js
render() {
return (
<div>
<div ref={el => this.mapContainer = el} />
</div>
)
}

The mapContainer ref specifies that map should be drawn to the HTML page in a new <div> element.

The map needs a few styling rules to render correctly. Add the following code to the site.css file:

site.css
.mapContainer {
position: absolute;
top: 0;
right: 0;
left: 0;
bottom: 0;
}

Next, update the return statement to specify that it needs to use this style by setting the React className to mapContainer:

index.js
render() {
return (
<div>
<div ref={el => this.mapContainer = el} className="mapContainer" />
</div>
)
}

Save your changes. In the command line, run the command npm start. This starts a local server and opens a new page in your browser that contains the new Mapbox map.

If you open your browser's developer console you may see an error: 'map' is assigned a value but never used. Don't worry — you will be using the map variable in the next step!

Store the new coordinates

Next, you need to create a function that stores the new latitude, longitude, and zoom that you get when a user interacts with the map. You will write a Mapbox GL JS map.on('move') function that resets the state to these new values when a user moves the map. Before the final curly brace of componentDidMount(), add the following code:

index.js
map.on('move', () => {
this.setState({
lng: map.getCenter().lng.toFixed(4),
lat: map.getCenter().lat.toFixed(4),
zoom: map.getZoom().toFixed(2)
});
});

When the map moves, this function uses setState() to reset the values of lng, lat, and zoom. It also uses the following methods:

  • getCenter(), a Mapbox GL JS method, to get the new longitude and latitude of the point at the center of the map.
  • getZoom(), a Mapbox GL JS method, to determine the zoom level that the map is set to.
  • toFixed(), a JavaScript method, to truncate the resulting floating point number to the specified number of digits.

Display the coordinates

Now that you are able to collect and store this information, you can use return to display it on the map. Inside the opening tag of the <div> you created to hold the map, add a new <div> that will be used to display the longitude, latitude, and zoom of the map. The return statement will look like this now:

index.js
render() {
return (
<div>
<div>
<div>Longitude: {this.state.lng} | Latitude: {this.state.lat} | Zoom: {this.state.zoom}</div>
</div>
<div ref={el => this.mapContainer = el} className='mapContainer' />
</div>
)
}

The sidebar needs a few styling rules to display on the page correctly. Add the following CSS to the site.css file:

site.css
.sidebarStyle {
display: inline-block;
position: absolute;
top: 0;
left: 0;
margin: 12px;
background-color: #404040;
color: #ffffff;
z-index: 1 !important;
padding: 6px;
font-weight: bold;
}

To apply these styles to the correct elements of the app, update the return statement in index.js:

index.js
render() {
return (
<div>
<div className='sidebarStyle'>
<div>Longitude: {this.state.lng} | Latitude: {this.state.lat} | Zoom: {this.state.zoom}</div>
</div>
<div ref={el => this.mapContainer = el} className='mapContainer' />
</div>
)
}

Save your work and go back to the browser page. There is a sidebar now in the upper left corner of the window that is styled according to the CSS rules you set in site.css. The sidebar shows the current latitude and longitude of the current center of the map, as well as the zoom level. Now when you zoom and pan around the map, the contents of the sidebar will update.

Final product

You have created a React app that uses Mapbox GL JS to render a map, display the center coordinates and the zoom level of the map, and then update that display when a user interacts with the map.

The final index.html page will look like the following:

index.html
<!DOCTYPE html>
<html lang='en'>
<head>
<title>Mapbox GL JS and React</title>
<meta charset='utf-8'>
<meta name='viewport' content='width=device-width, initial-scale=1'>
<link href='https://api.tiles.mapbox.com/mapbox-gl-js/v1.3.1/mapbox-gl.css' rel='stylesheet' />
<link href='site.css' rel='stylesheet'/>
</head>
<body>
<div id='app'></div>
</body>
</html>

The final index.js file will look like the following:

index.js
import React from 'react';
import ReactDOM from 'react-dom';
import mapboxgl from 'mapbox-gl';
mapboxgl.accessToken = 'YOUR_MAPBOX_ACCESS_TOKEN';
class Application extends React.Component {
constructor(props) {
super(props);
this.state = {
lng: 5,
lat: 34,
zoom: 2
};
}
componentDidMount() {
const map = new mapboxgl.Map({
container: this.mapContainer,
style: 'mapbox://styles/mapbox/streets-v11',
center: [this.state.lng, this.state.lat],
zoom: this.state.zoom
});
map.on('move', () => {
this.setState({
lng: map.getCenter().lng.toFixed(4),
lat: map.getCenter().lat.toFixed(4),
zoom: map.getZoom().toFixed(2)
});
});
}
render() {
return (
<div>
<div className='sidebarStyle'>
<div>Longitude: {this.state.lng} | Latitude: {this.state.lat} | Zoom: {this.state.zoom}</div>
</div>
<div ref={el => this.mapContainer = el} className='mapContainer' />
</div>
)
}
}
ReactDOM.render(<Application />, document.getElementById('app'));

The final site.css file will look like:

site.css
.sidebarStyle {
display: inline-block;
position: absolute;
top: 0;
left: 0;
margin: 12px;
background-color: #404040;
color: #ffffff;
z-index: 1 !important;
padding: 6px;
font-weight: bold;
}
.mapContainer {
position: absolute;
top: 0;
right: 0;
left: 0;
bottom: 0;
}

Next steps

Now that you have created a React app that uses Mapbox GL JS, you can explore other, more complex examples in the Mapbox React examples GitHub repository.

Was this page helpful?