Using Google Map in React Component
You're adding a <script>
tag to your document to load the Google Maps API, but you aren't waiting for it to actually load before running your initMap
method. Since it hasn't loaded yet, the google
variable doesn't yet exist.
You've added a parameter to the script's URL, callback
, with a value initMap
. The Google Maps API will see this and run a function called initMap
once it's ready. But your initMap
method is not available from the global scope, and so will not be run.
One way to fix your code would be to make yourself a promise for the Google Maps API, and resolve that promise in a (global) callback function the Google Maps API can run. In your component code you'd then wait for the promise to be resolved before proceeding.
That might look something like this:
class ContactBody extends React.Component {
getGoogleMaps() {
// If we haven't already defined the promise, define it
if (!this.googleMapsPromise) {
this.googleMapsPromise = new Promise((resolve) => {
// Add a global handler for when the API finishes loading
window.resolveGoogleMapsPromise = () => {
// Resolve the promise
resolve(google);
// Tidy up
delete window.resolveGoogleMapsPromise;
};
// Load the Google Maps API
const script = document.createElement("script");
const API = 'AIzaSyDbAz1XXxDoKSU2nZXec89rcHPxgkvVoiw';
script.src = `https://maps.googleapis.com/maps/api/js?key=${API}&callback=resolveGoogleMapsPromise`;
script.async = true;
document.body.appendChild(script);
});
}
// Return a promise for the Google Maps API
return this.googleMapsPromise;
}
componentWillMount() {
// Start Google Maps API loading since we know we'll soon need it
this.getGoogleMaps();
}
componentDidMount() {
// Once the Google Maps API has finished loading, initialize the map
this.getGoogleMaps().then((google) => {
const uluru = {lat: -25.363, lng: 131.044};
const map = new google.maps.Map(document.getElementById('map'), {
zoom: 4,
center: uluru
});
const marker = new google.maps.Marker({
position: uluru,
map: map
});
});
}
render() {
return (
<div>
<h1>Contact</h1>
<div id="map" style={{width: 400, height: 300}}></div>
</div>
)
}
}
ReactDOM.render(
<ContactBody />,
document.getElementById('react')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="react"></div>
Add script to head tag (my recommend is react-helmet) then equal window.initMap to your initialize map function because in script src define (callback=initMap"
) a global function named 'initMap'.
import React, { useEffect } from 'react';
import { Helmet } from 'react-helmet';
const Map = () => {
useEffect(() => {
window.initMap = () => {
new google.maps.Map(document.getElementById('map'), {
center: { lat: -34.397, lng: 150.644 },
zoom: 8,
});
};
}, []);
return (
<>
<Helmet>
<script src="https://maps.googleapis.com/maps/api/js key=?key=YOUR_API_KEY&callback=initMap" async defer />
</Helmet>
<div style={{ height: "100%" }} id="map"></div>
</>
);
};
If in server side rendered must check is in browser environment because window
in undefined in node.js environment:
... lang-js
if (process.browser) { // check browser environment
window.initMap = (): void => {
new google.maps.Map(document.getElementById('map'), {
center: { lat: -34.397, lng: 150.644 },
zoom: 8,
});
};
}
...
This is how I did it:
import React from 'react';
export default class GoogleMap extends React.Component {
constructor(props) {
super(props);
this.state = {
mapIsReady: false,
};
}
componentDidMount() {
const ApiKey = 'XXXXXXXXXXXXXXXXXXXX';
const script = document.createElement('script');
script.src = `https://maps.googleapis.com/maps/api/js?key=${ApiKey}`;
script.async = true;
script.defer = true;
script.addEventListener('load', () => {
this.setState({ mapIsReady: true });
});
document.body.appendChild(script);
}
componentDidUpdate() {
if (this.state.mapIsReady) {
// Display the map
this.map = new window.google.maps.Map(document.getElementById('map'), {
center: {lat: -34.397, lng: 150.644},
zoom: 12,
mapTypeId: 'roadmap',
});
// You also can add markers on the map below
}
}
render() {
return (
<div id="map" />
);
}
}
for those who are getting error google is not defined just above the error mentioned by eslint go ahead an define
const google = window.google;