Как добавить Google API скрипт при рендеринге компонента?

Я пытаюсь добавить скрипт Google API программно, когда это требуется. Однако я получаю сообщение об ошибке, что Google не определен. Я вижу, что скрипт добавляется до конца тега body.

Ранее у меня был скрипт, загруженный в файл index.html, однако теперь я создал другой компонент в другом месте приложения, для которого требуется собственный скрипт, так как он имеет другой ключ API. Поэтому мне пришлось удалить скрипт из index.html, так как он давал исключение для многократного использования скрипта. Теперь я хотел бы добавить его, когда он загружается.

Пожалуйста, используйте код ниже для основного компонента:

import React from 'react';
import { Button } from 'reactstrap';
import CitySuggestionBar from './CitySuggestionBar';

export default class Destination extends React.Component{

    componentDidMount(){
        this.renderScript();
    }

    renderScript = () => {
        loadScript('https://maps.googleapis.com/maps/api/js?key=MY_API_KEY&libraries=places');
      }

    showPlaceDetails(place) {
        let city = place.address_components[0].long_name.toString();
        try{
            city+= '+' + place.address_components[2].long_name.toString();
        }catch(e){}
        city = city.replace(/\s/g, "+");
        sessionStorage.setItem('city', city);
        console.log(city);
    }

    redirect = () =>{
        sessionStorage.getItem('city') ? this.props.history.push("/hotels") : alert('Please select a city first');
    }

    render(){
        return(
            <div className="location-search-container">
                <div className="location-search-wrapper">
                    <h1>Search for a city...</h1>
                    <CitySuggestionBar onPlaceChanged={this.showPlaceDetails.bind(this)} />
                    <Button onClick={this.redirect} className="btns" to="/hotels" color="primary">Proceed</Button>
                </div>
            </div>
        );
    }
}

const loadScript = (url) => {
    const index = window.document.getElementsByTagName('script')[0];
    const script = window.document.createElement('script');
    script.src=url;
    index.parentNode.insertBefore(script, index);

  }

Ниже приведен код компонента, в котором используется карта Google, и он является подкомпонентом вышеуказанного основного компонента:

import React from "react";
/* global google */


export default class CitySuggestionBar extends React.Component {
  constructor(props) {
    super(props);
    this.autocompleteInput = React.createRef();
    this.autocomplete = null;
    this.handlePlaceChanged = this.handlePlaceChanged.bind(this);
  }

  componentDidMount() {
    this.autocomplete = new window.google.maps.places.Autocomplete(this.autocompleteInput.current,
        {"types": ['(cities)']});

    this.autocomplete.addListener('place_changed', this.handlePlaceChanged);
  }



  handlePlaceChanged(){
    const place = this.autocomplete.getPlace();
    this.props.onPlaceChanged(place);
  }



  render() {
    return (
        <input ref={this.autocompleteInput}  id="autocomplete" placeholder="Search"
         type="text"></input>
    );
  }
}

Пожалуйста помоги! Заранее спасибо.

1 ответ

В приведенном выше фрагменте я вижу, что каждый раз, когда componentDidMount снова создает новый тег сценария, чтобы избежать этого, вы можете изменить методы loadScript следующим образом:

const loadScript = (url) => {
    const googleScript = window.document.getElementByClassName('google-script');
    if (googleScript.length === 0) {
        const script = window.document.createElement('script');
        script.src=url;
        script.class="google-script"
        document.body.appendChild(script)
    }
}

Если вы хотите удалить скрипт Google, вы можете справиться с этим внутри componentWillUnmount.

Использование этого не покажет вам исключение для многократного использования тега script.

Также, если вы хотите знать, загружен тег script или нет, вы можете найти его, добавив другой метод, аналогичный методу loadScript, следующим образом:

const loadScript = (url) => {
    const googleScript = window.document.getElementByClassName('google-script');
    if (googleScript.length === 0) {
        const script = window.document.createElement('script');
        script.src=url;
        script.class="google-script"
        document.body.appendChild(script)
        script.onload = () => {
            // Place code here to do further action.
        };
    }
}

<---------------------------- Update -------------------- ------->

Чтобы устранить ошибку "Google is undefined", вы можете попробовать придерживаться подхода, в котором вы создаете обещание для API Карт Google, и разрешить это обещание в (глобальной) функции обратного вызова, которую может запустить API Карт Google. В коде компонента вы должны дождаться разрешения обещания, прежде чем продолжить.

const loadScript = () => {
  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 = //your api key;
        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.loadScript();
}

componentDidMount() {
  // Once the Google Maps API has finished loading, initialize the map
  this.getGoogleMaps().then((google) => {
    const uluru = { lat: -25.366, 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>
      <div id="map" style={{width: 600, height: 300}}></div>
    </div>
  )
}
Другие вопросы по тегам