在React组件中使用Google Map

时间:2018-01-29 03:28:32

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

我正在尝试在React Component中使用Google Map,但它似乎不起作用。 我目前指的是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>

然而,当我运行这个时,我得到“未捕获的ReferenceError:google未定义”

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

谢谢。

7 个答案:

答案 0 :(得分:17)

您正在为文档添加<script>标记以加载Google Maps API,但在运行initMap方法之前,您还没有等待它实际加载。由于尚未加载,google变量尚未存在。

您已在脚本的网址callback中添加了参数,其值为initMap。 Google Maps API会看到此内容,并在准备好后运行名为initMap的函数。但您的 initMap方法无法在全局范围内使用,因此无法运行。

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

这可能看起来像这样:

&#13;
&#13;
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')
);
&#13;
<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>
&#13;
&#13;
&#13;

答案 1 :(得分:5)

对于那些遇到错误的人google并没有在eslint提到的错误之上定义

list = new ArrayList<>();
int execptedResult = NUMBER_OF_RESULT; // <--- you must fetch data from firebase in some way, it depends on your implementation 
int fetchCount = 0;
DatabaseReference reference = FirebaseDatabase.getInstance().getReference().child("FacultyMember");
reference.addValueEventListener(new ValueEventListener()
{
    @Override
    public void onDataChange(DataSnapshot dataSnapshot)
    {
        for (DataSnapshot ds : dataSnapshot.getChildren())
        {
            fetchCount++;
            String Name = ds.child("Name").getValue().toString();
            list.add(Name);
            Toast.makeText(getApplicationContext(),Name,Toast.LENGTH_LONG).show();
            if(fetchCount == execptedResult){
                AlertDialog.Builder builder =new AlertDialog.Builder(AdminHome.this);
                builder.setTitle("Member List");
                builder.setIcon(R.drawable.ic_format_list_bulleted_black_24dp);
                builder.setItems(list.toArray(new String[0]), new 
                    DialogInterface.OnClickListener()
                    {
                        @Override
                        public void onClick(DialogInterface dialogInterface, int i)
                        {

                        }
                    });
            }
        }
    }

    @Override
    public void onCancelled(DatabaseError databaseError) {

    }
});

答案 2 :(得分:4)

这是我的方法:

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 :(得分:1)

将脚本添加到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,
    });
  };
}
...

答案 4 :(得分:0)

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

答案 5 :(得分:0)

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

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 :(得分:0)

在 React 应用中,

在 index.html 中使用脚本标签加载谷歌地图 api 不起作用,会给你错误访问源拒绝 .....

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

例如,我简单地使用 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 (

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

              process.env.REACT_APP_GOOGLEMAPS_API_KEY

.env 文件应该放在根文件夹中,与 package.json 所在的位置相同,所以 .env 文件应该放在 package.json 文件旁边。

这是 .env 文件的样子:

              REACT_APP_GOOGLEMAPS_API_KEY=AIzajfU2J8m4vE 

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