reactjsgoogle-mapsgoogle-apigoogle-directions-apireact-google-maps

react-google-maps/api DirectionsService keeps rerendering itself


I have written this code in react JS to using "react-google-maps/api" to calculate route between two points. Now my google map keeps rerendering itself until it gives "DIRECTIONS_ROUTE: OVER_QUERY_LIMIT" error. I don't know what's the issue. Help would be appreciated because I am a beginner in react and google-API and also I haven't found a lot of guides of google API in react.

Here is my code:

import React from "react";
import {
  GoogleMap,
  useLoadScript,
  DirectionsService,
  DirectionsRenderer,
} from "@react-google-maps/api";

const libraries = ["places", "directions"];
const mapContainerStyle = {
  width: "100%",
  height: "50vh",
};
const center = {
  lat: 31.582045,
  lng: 74.329376,
};
const options = {};

const MainMaps = () => {
  const { isLoaded, loadError } = useLoadScript({
    googleMapsApiKey: "********",
    libraries,
  });

  const [origin2, setOrigin2] = React.useState("lahore");
  const [destination2, setDestination2] = React.useState("gujranwala");
  const [response, setResponse] = React.useState(null);

  const directionsCallback = (response) => {
    console.log(response);

    if (response !== null) {
      if (response.status === "OK") {
        setResponse(response);
      } else {
        console.log("response: ", response);
      }
    }
  };

  const mapRef = React.useRef();
  const onMapLoad = React.useCallback((map) => {
    mapRef.current = map;
  }, []);
  if (loadError) return "Error loading maps";
  if (!isLoaded) return "loading maps";

  const DirectionsServiceOption = {
    destination: destination2,
    origin: origin2,
    travelMode: "DRIVING",
  };

  return (
    <div>
      <GoogleMap
        mapContainerStyle={mapContainerStyle}
        zoom={8}
        center={center}
        onLoad={onMapLoad}
      >
        {response !== null && (
          <DirectionsRenderer
            options={{
              directions: response,
            }}
          />
        )}

        <DirectionsService
          options={DirectionsServiceOption}
          callback={directionsCallback}
        />
      </GoogleMap>
    </div>
  );
};

export default MainMaps;

Solution

  • The rendering issue appears to be with the library itself. One alternative I can suggest is to instead use/load Google Maps API script instead of relying on 3rd party libraries. This way, you can just follow the official documentation provided by Google.

    By loading the script, we can now follow their Directions API documentation:

    Here is a sample app for your reference: https://stackblitz.com/edit/react-directions-64165413

    App.js

    
        import React, { Component } from 'react';
        import { render } from 'react-dom';
        import Map from './components/map';
        import "./style.css";
        
        class App extends Component {
         
          render() {
            return (
               <Map 
                id="myMap"
                options={{
                  center: { lat: 31.582045, lng: 74.329376 },
                  zoom: 8
                }}
              />
            );
          }
        }
        
        export default App;
    
    

    map.js

    
        import React, { Component } from "react";
        import { render } from "react-dom";
        
        class Map extends Component {
          constructor(props) {
            super(props);
            this.state = {
              map: "",
              origin: "",
              destination: ""
            };
            this.handleInputChange = this.handleInputChange.bind(this); 
            this.onSubmit = this.onSubmit.bind(this);
          }
        
          onScriptLoad() {
            this.state.map = new window.google.maps.Map(
              document.getElementById(this.props.id),
              this.props.options
            );
          }
        
          componentDidMount() {
            if (!window.google) {
              var s = document.createElement("script");
              s.type = "text/javascript";
              s.src = `https://maps.google.com/maps/api/js?key=YOUR_API_KEY`;
              var x = document.getElementsByTagName("script")[0];
              x.parentNode.insertBefore(s, x);
              // Below is important.
              //We cannot access google.maps until it's finished loading
              s.addEventListener("load", e => {
                this.onScriptLoad();
              });
            } else {
              this.onScriptLoad();
            }
          }
        
          onSubmit(event) {    
            this.calculateAndDisplayRoute();
            event.preventDefault();
          }
        
          calculateAndDisplayRoute() {
            var directionsService = new google.maps.DirectionsService();
            var directionsRenderer = new google.maps.DirectionsRenderer();
            directionsRenderer.setMap(this.state.map);
            directionsService.route(
              {
                origin: { query: this.state.origin },
                destination: { query: this.state.destination },
                travelMode: "DRIVING"
              },
              function(response, status) {
                if (status === "OK") {
                  directionsRenderer.setDirections(response);
                } else {
                  window.alert("Directions request failed due to " + status);
                }
              }
            );
            
          }
        
          handleInputChange(event) {
            const target = event.target;
            const value = target.type === "checkbox" ? target.checked : target.value;
            const name = target.name;
        
            this.setState({
              [name]: value
            });
          }
          addMarker(latLng) {
            var marker = new window.google.maps.Marker({
              position: { lat: -33.8569, lng: 151.2152 },
              map: this.state.map,
              title: "Hello Sydney!"
            });
            var marker = new google.maps.Marker({
              position: latLng,
              map: this.state.map
            });
          }
        
          render() {
            return (
              <div>
                <input
                  id="origin"
                  name="origin"
                  value={this.state.origin}
                  placeholder="Origin"
                  onChange={this.handleInputChange}
                />
                <input
                  id="destination"
                  name="destination"
                  value={this.state.destination}
                  placeholder="Destination"
                  onChange={this.handleInputChange}
                />
                <button id="submit" onClick={this.onSubmit}>
                  Search
                </button>
                <div className="map" id={this.props.id} />
              </div>
            );
          }
        }
        
        export default Map;