Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using Google Map in React Component

I am trying to use Google Map in React Component and it doesn't seem to work. I am currently referring to https://developers.google.com/maps/documentation/javascript/adding-a-google-map

Here is the code that I have for my component:

class ContactBody extends React.Component {
  componentWillMount() {
    const script = document.createElement("script");
    const API = 'AIzaSyDbAz1XXxDoKSU2nZXec89rcHPxgkvVoiw';
    script.src = `https://maps.googleapis.com/maps/api/js?key=${API}&callback=initMap`;
    script.async = true;

    document.body.appendChild(script);
  };

  initMap() {
    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() {
    
    this.initMap();
    
    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>

However, when I run this, I am getting "Uncaught ReferenceError: google is not defined"

Could anyone tell me what is wrong with my code?

Thank you.

like image 472
Eunicorn Avatar asked Jan 29 '18 03:01

Eunicorn


2 Answers

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" />
    );
  }
}
like image 129
Michael Yurin Avatar answered Sep 20 '22 13:09

Michael Yurin


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>
like image 34
tremby Avatar answered Sep 19 '22 13:09

tremby