简体   繁体   中英

How to load the google maps api <script> in my react app only when it is required?

I want to try and use the google maps API to show a map but I'm wondering if there's a better way to load the <script> tag than putting it in my index.html.

I would like for the script to load only when I go to the /map route. So, I would want to remove it from my index.html and load it dynamically. However, I also want to make sure that if its already been loaded that I don't try and load it again.

I'm not sure if there is a library to handle this. What I've tried so far (but failed) is to create a loadScript function which appends a <script> to the actual dom and assigns it a key so in this case 'google-maps .

Thanks

Updates Oct 6, 2019 : The example code is still working well, I have just updated them to use non-decorator syntax.


This is what I make it worked in my recent project. I used react-async-script-loader component.

import React from 'react';
import scriptLoader from 'react-async-script-loader';

class Maps extends React.Component {
  constructor(props) {
    super(props);
    this.map = null;
  }

  componentWillReceiveProps({ isScriptLoaded, isScriptLoadSucceed }) {
    if (isScriptLoaded && !this.props.isScriptLoaded) {
      // load finished
      if (isScriptLoadSucceed) {
        this.map = new google.maps.Map(this.refs.map, {
          center: { lat: 10.794234, lng: 106.706541 },
          zoom: 20
        });

        if (navigator.geolocation) {
          navigator.geolocation.getCurrentPosition(
            position => {
              const pos = {
                lat: position.coords.latitude,
                lng: position.coords.longitude
              };

              this.map.setCenter(pos);

              const marker = new google.maps.Marker({
                position: pos,
                map: this.map,
                title: 'Hello World!'
              });
            },
            () => {
              console.log('navigator disabled');
            }
          );
        } else {
          // Browser doesn't support Geolocation
          console.log('navigator disabled');
        }
      } else this.props.onError();
    }
  }

  render() {
    return (
      <div>
        <div ref="map" style={{ height: '80%', width: '100%' }}></div>
        {!this.map && <div className="center-md">Loading...</div>}
      </div>
    );
  }
}

export default scriptLoader(['https://maps.googleapis.com/maps/api/js?key=API_KEY'])(Maps);

Thanks Nguyen Thanh . As google now in global scope I used window.google .

import React, { Component } from 'react';
import scriptLoader from 'react-async-script-loader';
class Map extends Component{
    constructor(props) {
        super(props);
    }
    componentWillReceiveProps({isScriptLoadSucceed}){
        if (isScriptLoadSucceed) {
            var markers = [];

            var map = new window.google.maps.Map(document.getElementById('map'), {
                zoom: 12,
                center: {lat: 37.7749300, lng: -122.4194200}
            });
        }
        else{
            alert("script not loaded")
        }
    }

    render(){
        return(
            <div>
                <div id="map" style={{height: "600px"}}></div>
            </div>
        )
    }
}

export default scriptLoader(
    ["https://maps.googleapis.com/maps/api/js?key= APIKEY"]
)(Map)

With react hook we can also load external script

https://usehooks.com/useScript/

//useScript custom hooks from the site

let cachedScripts = [];

function useScript(src) {
  // Keeping track of script loaded and error state

  const [state, setState] = useState({
    loaded: false,
    error: false
  });

  useEffect(
    () => {
      // If cachedScripts array already includes src that means another instance ...
      // ... of this hook already loaded this script, so no need to load again.
      if (cachedScripts.includes(src)) {
        setState({
          loaded: true,

          error: false
        });
      } else {
        cachedScripts.push(src);
        // Create script
        let script = document.createElement("script");
        script.src = src;
        script.async = true;
        // Script event listener callbacks for load and error
        const onScriptLoad = () => {
          setState({
            loaded: true,
            error: false
          });
        };

        const onScriptError = () => {
          // Remove from cachedScripts we can try loading again
          const index = cachedScripts.indexOf(src);
          if (index >= 0) cachedScripts.splice(index, 1);
          script.remove();
          setState({
            loaded: true,
            error: true
          });
        };
        script.addEventListener("load", onScriptLoad);
        script.addEventListener("error", onScriptError);
        // Add script to document body
        document.body.appendChild(script);
        // Remove event listeners on cleanup
        return () => {
          script.removeEventListener("load", onScriptLoad);
          script.removeEventListener("error", onScriptError);
        };
      }
    },
    [src] // Only re-run effect if script src changes
  );
  return [state.loaded, state.error];
}


Usage

//App.js
import React from "react";
import ReactDOM from "react-dom";
import { useState, useEffect } from "react";
function App() {
  const [loaded, error] = useScript(
    "https://maps.googleapis.com/maps/api/js?key=API_KEY"
  );
  useEffect(() => {
    if (loaded) {
      new window.google.maps.Map(document.getElementById("map"), {
        zoom: 12,
        center: { lat: 37.77493, lng: -122.41942 }
      });
    }
  }, [loaded]);

  return (
    <div>
      <div>
        Script loaded: <b>{loaded.toString()}</b>
      </div>
      <div id="map" style={{ height: "600px" }} />
    </div>
  );
}

Yet another package react-dependent-script package to load Google Maps libraries, which provides the following features:

  • ensure to load the JavaScript and/or CSS first, then render your content
  • ensures the external content is only loaded once, regardless of how many times the render() function is called

Here is a simple example, where you wrap your map component in ReactDependentScript component:

<ReactDependentScript
      scripts={[
        "https://maps.googleapis.com/maps/api/js?key={YOUR-KEY-GOES-HERE}"
      ]}>
      <Map center={{ lat: -34.397, lng: 150.644 }} zoom={3} />
</ReactDependentScript>

Here is a demo for your reference

As of April 2021 Google has " made it easier to use the Maps JavaScript API in modern web apps " more details on their blog post: Loading Google Maps Platform JavaScript in Modern Web Applications .

This are the instructions for the Google Maps JavaScript API Loader library

import { Loader } from '@googlemaps/js-api-loader';

const loader = new Loader({
  apiKey: "",
  version: "weekly",
  libraries: ["places"]
});

const mapOptions = {
  center: {
    lat: 0,
    lng: 0
  },
  zoom: 4
};

// Promise
loader
  .load()
  .then((google) => {
    new google.maps.Map(document.getElementById("map"), mapOptions);
  })
  .catch(e => {
    // do something
  });

Or if you want, you can use the Google Maps JavaScript API React Wrapper library .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM