【问题标题】:Using Google Map in React Component在 React 组件中使用谷歌地图
【发布时间】:2018-07-07 17:13:24
【问题描述】:

我正在尝试在 React 组件中使用 Google 地图,但它似乎不起作用。 我目前指的是https://developers.google.com/maps/documentation/javascript/adding-a-google-map

这是我的组件的代码:

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>

但是,当我运行它时,我收到“Uncaught ReferenceError: google is not defined”

谁能告诉我我的代码有什么问题?

谢谢。

【问题讨论】:

  • 您是否已将https://maps.googleapis.com/maps/api/js?key=${API}&amp;callback=initMap; 添加到您的index.html 文件中?

标签: javascript reactjs google-maps redux google-maps-markers


【解决方案1】:

您正在将&lt;script&gt; 标记添加到您的文档以加载Google Maps API,但在运行initMap 方法之前您无需等待它实际加载。由于尚未加载,google 变量还不存在。

您已将参数callback 添加到脚本的URL,其值为initMap。 Google Maps API 将看到这一点,并在准备好后运行一个名为 initMap 的函数。但是您的initMap 方法在全局范围内不可用,因此不会运行。

修复代码的一种方法是让自己成为 Google Maps API 的承诺,并在 Google Maps API 可以运行的(全局)回调函数中解决该承诺。在您的组件代码中,您将等待承诺得到解决,然后再继续。

可能看起来像这样:

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>

【讨论】:

  • 我偶然发现了您的代码并尝试了它,因为我也面临将 Google 地图作为组件加载的问题...碰巧我收到错误 'google' is not defined from the line resolve (谷歌)。有什么我似乎缺少的东西吗? @tremby
  • 我上面的示例代码至少在我的浏览器中工作(单击“运行代码 sn-p”,你应该得到一个带有标记的地图)。您描述的错误意味着 window.resolveGoogleMapsPromise 方法在它应该运行之前运行。寻找对它的意外调用。或发布您的代码;否则我无法为您提供更多帮助。
  • 在我在代码顶部添加 /* global google */ 后,这非常有效。将来可能对使用 create-react-app 方式的人有用。 :)
  • 好的,听起来您的构建链与问题有关。
  • 据我所知,/* global google */ 等 cmets 中的指令不是 ES6 的一部分。看起来像是在暗示 linter。
【解决方案2】:

我就是这样做的:

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" />
    );
  }
}

【讨论】:

    【解决方案3】:

    对于那些遇到错误的人,谷歌没有在 eslint 提到的错误之上定义,请继续定义

    const google = window.google;
    

    【讨论】:

      【解决方案4】:

      将脚本添加到 head 标签(我的推荐是 react-helmet)然后等于 window.initMap 到您的初始化映射函数,因为在脚本 src 中定义(callback=initMap")一个名为“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>
          </>
        );
      };
      

      如果在服务器端渲染必须检查是否在浏览器环境中,因为 window 在 node.js 环境中未定义:

      ... 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,
          });
        };
      }
      ...
      

      【讨论】:

        【解决方案5】:

        如果您在 index.html 中包含 Google API 脚本,则无需 createElement在组件DidMount() 中。 你可以做这样的事情-

        import React from 'react';
        export default class GoogleMap extends React.Component {
          constructor(props) {
            super(props);
            this.state = {
              mapIsReady: false,
            };
          }
        
          componentDidMount() {
            //Load Map after DOM is loaded
            window.onload = this.setState({mapIsReady : true});
          }
        
          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"></div>
            );
          }
        }
        

        【讨论】:

          【解决方案6】:

          在反应应用中,

          在 index.html 中使用脚本标签加载 google maps api 不起作用,会给你错误 Access origin denied .....

          解决方法是在下游模块系统中加载 google map api,使用 useEffect() hook。

          例如,我简单地使用 app.js 加载 api,您可以使用任何组件来这样做。不需要是app.js

          这是我的工作代码:

                           import React, { useState, useEffect } from 'react';
          
                            function App() {
          
                                 useEffect(() => {
          
          
                                      const googleMapScript = document.createElement('script');
                                      googleMapScript.src=`https://maps.googleapis.com/maps/api/js?key=${process.env.REACT_APP_GOOGLEMAPS_API_KEY}&libraries=places&callback=initMap`;
                                      googleMapScript.async = true;
                                      window.document.body.appendChild(googleMapScript);
          
                                }); 
          
              return (
          

          不要忘记将您的 google map api 密钥放在 .env 文件中, 所以你可以把它称为

                        process.env.REACT_APP_GOOGLEMAPS_API_KEY
          

          .env 文件应该放在你的 package.json 所在的根文件夹中,所以 .env 文件应该放在 package.json 文件旁边。

          这是 .env 文件的样子:

                        REACT_APP_GOOGLEMAPS_API_KEY=AIzajfU2J8m4vE 
          

          请记住,您的密钥必须以“REACT_APP_”开头

          【讨论】:

            【解决方案7】:

            尝试在页面顶部输入此内容(对我有用) - /* global google */

            【讨论】:

              猜你喜欢
              • 2016-10-12
              • 2020-10-31
              • 2018-07-03
              • 2019-01-08
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2021-10-09
              • 2022-08-03
              相关资源
              最近更新 更多