Implement Google Maps into your React Project

Today I’m going to be going over a short guide on how to drop a Google Map component into your React project. The official NPM documentation for the library I’m using has all the instructions here if you would like to check that out instead.

Setup

First things first, go here to sign up for your API key. If you’ve done this kind of thing before, its fairly straight forward. Otherwise, you’ll need to sign up and add a new set of credentials. It’ll ask for the project name and whatnot. The url you’ll want to use while in development is localhost:3000 (React’s default).

REACT_APP_GMAPS_KEY=<API key here, no spaces, no quotes/>

The Map

Google Maps API has an extensive list of different API services. The specific one we will use to drop in your map is the Maps JavaScript API. You can read the documentation on that API here. It’s important that you also activate this API for use. Go to the Google Dev console where your credentials for this project are stored and enable the Maps JavaScript API. This API is what is going to present your Map component with the info it needs.

npm install google-maps-react --save
import React, { Component } from 'react';
import { Map, GoogleApiWrapper, Marker, InfoWindow } from 'google- maps-react';
require('dotenv').config();
export default class MapContainer extends Component {
state = {
destinations: [],
mapCenter: { lat: 30.146626, lng: -92.035548 }
}
render() {
const mapStyles = {
height: "70%",
width: "50%",
position: "static"
}
return(
<div className="map-container">
<Map
google={this.props.google}
initialCenter={this.state.mapCenter}
style={mapStyles}
zoom={14}
className={"map"}>
</Map>
</div>
)
}
}
export default GoogleApiWrapper({
apiKey: process.env.REACT_APP_GMAPS_KEY
})(MapContainer);
  • intialCenter quite literally tells our map where to center itself. Passing the state object the way its formatted above will do the trick
  • zoom tells how far we want the map to be zoomed
  • style gives the Map some initial style properties. I like to create a separate object, but you can pass it as a raw object in the props if you choose to do so
  • className is my personal preference. The different tutorials I’ve seen render a map that covers the whole screen, but in my instance I wanted a smaller map centered to the screen. This can be done by giving class names to the Map and its parent <div> and using CSS:
.map-container, .map {
display: flex;
justify-content: center;
}

Marker and InfoWindow

And important thing to note about both of these components is that they are both child components of <Map />. So the first step I want to take is adding some other state values we are going to need. Ultimately, the component state should look like this to start:

state = {
destinations: [
{location: { lat: 30.150839490122195, lng: -92.09357565868899},
name: "Address 1"},
{location: { lat: 30.10956547664899, lng: -92.05924338426283},
name: "Address 2"}
],
mapCenter: { lat: 30.146626, lng: -92.035548 },
showInfoWindow: false,
activeMarker: {},
selectedPlace: {}
}
<Map>
<Marker
position={this.state.mapCenter}
name={"Center Marker"}
icon={{
url: './center-marker.png',
scaledSize: new this.props.google.maps.Size(37, 37)
}}
/>
</Map>
  • name is the name. That’s it.
  • icon allows you to specify your own custom icon. It accepts an object with a url key and a scaledSize key. The cool thing about this component is that if you have an image in your public directory (which is where you should be storing project images to be rendered) the above url path will work just fine. The scaledSize prop uses that complicated google prop mentioned earlier to allow you to resize your custom icon based on the Map’s size. The two numbers specify height and width, and will greatly vary on the size of your Map. You’ll probably need to play with this to get it just right.
renderDestinations = () => {
if (this.state.destinations.length > 0) {
return this.state.destinations.map(destination => {
return <Marker
position={destination.location}
name={destination.name}
icon={{
url: './marker.png',
scaledSize: this.props.google.maps.Size(37, 37)
}}
/>
})
}
}
<Marker />
{this.renderDestinations()}
onMarkerClick = (props, marker, event) => {
this.setState({
selectedPlace: props,
activeMarker: marker,
showInfoWindow: true
})
}
<Map>
<Marker />
{this.renderDestinations()}
<InfoWindow
visible={this.state.showInfoWindow}
marker={this.props.activeMarker}
onClose={this.onClose}>
<div className="marker-info">
<h4>{this.state.selectedPlace.name}</h4>
</div>
</InfoWindow>
</Map>
  • marker is the marker that the InfoWindow will attach itself to. This is set by the onMarkerClick() function from earlier.
  • onClose() is an event listener that will detach the window from the Marker when we close the window. We can go straight into building that now:
onClose = props => {
if (this.state.showInfoWindow) {
this.setState({
showInfoWindow: false,
activeMarker: {},
selectedPlace: {}
})
}
}

The Final Product

import React, { Component } from 'react';
import { Map, GoogleApiWrapper, Marker, InfoWindow } from 'google- maps-react';
require('dotenv').config();
state = {
destinations: [
{location: { lat: 30.150839490122195, lng: -92.09357565868899},
name: "Address 1"},
{location: { lat: 30.10956547664899, lng: -92.05924338426283},
name: "Address 2"}
],
mapCenter: { lat: 30.146626, lng: -92.035548 },
showInfoWindow: false,
activeMarker: {},
selectedPlace: {}
}
renderDestinations = () => {
if (this.state.destinations.length > 0) {
return this.state.destinations.map(destination => {
return <Marker
position={destination.location}
onClick={this.onMarkerClick}
name={destination.name}
icon={{
url: './marker.png',
scaledSize: this.props.google.maps.Size(37, 37)
}}
/>
})
}
}
onMarkerClick = (props, marker, event) => {
this.setState({
selectedPlace: props,
activeMarker: marker,
showInfoWindow: true
})
}
onClose = props => {
if (this.state.showInfoWindow) {
this.setState({
showInfoWindow: false,
activeMarker: {},
selectedPlace: {}
})
}
}
render() {
const mapStyles = {
height: "70%",
width: "50%",
position: "static"
}
return(
<div className="map-container">
<Map
google={this.props.google}
initialCenter={this.state.mapCenter}
style={mapStyles}
zoom={14}
className={"map"}>
<Marker
position={this.state.mapCenter}
name={"Center Marker"}
onClick={this.onMarkerClick}
icon={{
url: './center-marker.png',
scaledSize: new this.props.google.maps.Size(37, 37)
}}
/>
{this.renderDestinations()}
<InfoWindow
visible={this.state.showInfoWindow}
marker={this.props.activeMarker}
onClose={this.onClose}>
<div className="marker-info">
<h4>{this.state.selectedPlace.name}</h4>
</div>
</InfoWindow>
</Map>
</div>
)
}
}
export default GoogleApiWrapper({
apiKey: process.env.REACT_APP_GMAPS_KEY
})(MapContainer);

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store