使用Google Maps API和google-maps-react进行React Apps

This tutorial aims at integrating the google maps API to your React components and enabling you to display maps on your website.

本教程旨在将google maps API集成到您的React组件中,并使您能够在网站上显示地图。

Google Maps API简介。 (Introduction to Google Maps API.)

At some point of our lives, we've all gotten a chance to use and interact with the google maps, either through finding directions, viewing our current location, ordering cabs or estimating distance and time from one point to another.

在我们生活的某个时刻,我们所有人都有机会使用Google地图并与之互动,方法是查找方向,查看我们的当前位置,订购出租车或估算从一点到另一点的距离和时间。

Including the Google maps API in a React App is actually far much easier than expected due to its rich documentation which I highly suggest that you look into, and the npm package by Fullstack React.

实际上,由于其丰富的文档 (我强烈建议您研究一下)以及Fullstack React的npm软件包 ,因此在React App中包括Google Maps API实际上比预期的要容易得多。

先决条件: ( Prerequisite: )

  • React Knowledge (at least intermediate level)

    React知识(至少中级水平)
  • A Google Maps API Key

    Google Maps API密钥

Go on ahead and grab your API key here.

继续,在这里获取您的API密钥

  1. Simply click on the Get Started button

    只需单击“入门”按钮
  2. Tick on the maps checkbox

    勾选地图复选框
  3. Click Create A New Project

    单击创建一个新项目
  4. Once you’ve named your project (whatever you want) you can set up your billing info which will automatically enable your the API and generate the API key.

    为项目命名后(无论您要使用什么名称),您都可以设置结算信息,这将自动启用您的API并生成API密钥。

PS: Do not be hesitant of adding your billing info as the Google cloud platform offers you a 12-month free trial period and will not bill you after the trial period until you give your permission.

PS:不要犹豫,添加您的帐单信息,因为Google云平台为您提供12个月的免费试用期,并且在您允许之前不会向您收费。

billingInfo.png

项目设置 ( Project Setup )

For some quick setup, we are going to use facebook's create-react-app which saves us the hassle of having to configure webpack or babel.

为了进行一些快速设置,我们将使用Facebook的create-react-app ,这免除了我们配置webpack或babel的麻烦。

So go on ahead and run this command

因此,继续执行此命令

npm i -g create-react-app
create-react-app my-googlemap
cd my-googlemap

Before we add any code, let’s go ahead and install our dependency.

在添加任何代码之前,让我们继续安装我们的依赖项。

npm install --save google-maps-react

Let's go on and edit our src folder and remove files and imports that we do not need ie

让我们继续编辑我们的src文件夹,并删除我们不需要的文件和导入,即

  1. logo.svg

    logo.svg
  2. App.css

    App.css
  3. index.css

    index.css
  4. In index.js remove the css import.

    index.js删除css导入。

是时候创建我们的组件了。 (Time to create our component.)

We will need to edit our App.js file and instead have our component that will load our google map.

我们将需要编辑App.js文件,而要使用我们的组件来加载Google地图。

import React, { Component } from 'react';
import { Map, GoogleApiWrapper } from 'google-maps-react';

const mapStyles = {
  width: '100%',
  height: '100%'
};

export class MapContainer extends Component {
  render() {
    return (
      <Map
        google={this.props.google}
        zoom={14}
        style={mapStyles}
        initialCenter={{
         lat: -1.2884,
         lng: 36.8233
        }}
      />
    );
  }
}

export default GoogleApiWrapper({
  apiKey: 'YOUR_GOOGLE_API_KEY_GOES_HERE'
})(MapContainer);

For a simple Google Map, this is literally all the code you need. Go ahead and run your app and ensure that the map loads to the browser.

对于简单的Google Map,这实际上就是您需要的所有代码。 继续并运行您的应用程序,并确保将地图加载到浏览器。

map.png

The Map component takes in some optional props such as style(the CSS style object), Zoom(number value representing a tighter focus on the map's center) and initialCenter(an object containing latitude and longitude coordinates)

Map组件带有一些可选的道具,例如style(CSS样式对象),Zoom(表示在地图中心的焦点的数字值)和initialCenter(包含纬度和经度坐标的对象)

The GoogleApiWrapper is simply a Higher Order Component(HOC) that provides wrapper around Google APIs. Alternatively, the GoogleApiWrapper HOC can be configured by passing a function that will be called with the wrapped component's props and should return the configuration object like so.

GoogleApiWrapper只是一个高阶组件(HOC) ,它提供了围绕Google API的包装器。 或者,可以通过传递一个函数来配置GoogleApiWrapper HOC,该函数将使用包装的组件的props调用,并且应该像这样返回配置对象。

export default GoogleApiWrapper(
  (props) => ({
    apiKey: props.apiKey
  }
))(MapContainer)

标记和infoWindow ( Markers and infoWindow )

Wouldn't it be exciting to have a Marker and an infoWindow on our map showing our set initialCenter position? So let's add this functionality to our code.

在我们的地图上显示我们设置的initialCenter位置的MarkerinfoWindow会不会令人兴奋? 因此,让我们将此功能添加到我们的代码中。

First we need to import Marker and infoWindow components from the google-maps-react library inorder to help us achieve loading of the two.

首先,我们需要从google-maps-react库导入MarkerinfoWindow组件,以帮助我们实现两者的加载。

import { GoogleApiWrapper, InfoWindow, Marker } from 'google-maps-react';

Notice that our component before was stateless?, We need to add state for state management.

注意,我们之前的组件是无状态的吗?,我们需要为状态管理添加状态。

[...]

export class MapContainer extends Component {
   state = {
    showingInfoWindow: false,  //Hides or the shows the infoWindow
    activeMarker: {},          //Shows the active marker upon click
    selectedPlace: {}          //Shows the infoWindow to the selected place upon a marker
  };

Next, we need to add event handlers for when the map and the marker are clicked.

接下来,我们需要为单击地图和标记的时间添加事件处理程序。

onMarkerClick = (props, marker, e) =>
    this.setState({
      selectedPlace: props,
      activeMarker: marker,
      showingInfoWindow: true
    });

  onClose = props => {
    if (this.state.showingInfoWindow) {
      this.setState({
        showingInfoWindow: false,
        activeMarker: null
      });
    }
  };
  • The onMarkerClick is used to show the InfoWindow which is a component in the google-maps-react library which gives us the ability for a pop-up window showing details of the clicked place/marker.

    onMarkerClick用于显示InfoWindow,它是google-maps-react库中的一个组件,它使我们能够使用弹出窗口来显示单击的位置/标记的详细信息。

Sidenote: the visibility of the infoWindow is controlled by the boolean visible prop which shows the InfoWindow component when true and hides it when false.

旁注:infoWindow的可见性由布尔可见道具控制,该道具在true时显示InfoWindow组件,在false时隐藏它。

  • The onClose basically is for closing the InfoWindow once a user clicks on the close button on the infoWindow.

    onClose基本上用于在用户单击infoWindow上的关闭按钮后关闭InfoWindow。

Let's complete our component by adding our Marker and InfoWindow components to our render method

让我们通过将Marker和InfoWindow组件添加到render方法来完善我们的组件

render() {
    return (
      <Map
        google={this.props.google}
        zoom={14}
        style={style}
        initialCenter={{ lat: -1.2884, lng: 36.8233 }
      >
        <Marker
          onClick={this.onMarkerClick}
          name={'Kenyatta International Convention Centre'}
        />
        <InfoWindow
          marker={this.state.activeMarker}
          visible={this.state.showingInfoWindow}
          onClose={this.onClose}
        >
          <div>
            <h4>{this.state.selectedPlace.name}</h4>
          </div>
        </InfoWindow>
      </Map>
    );
  }
}

[...]

Run your app and ensure you have the one marker with the infoWindow upon click.

运行您的应用程序,并确保单击时有一个带有InfoWindow的标记。

mapWithMarker.png

  • TODO: Try and add a few more markers on your map and more interactivity to your infoWindow.

    待办事项:尝试在地图上添加更多标记,并增加与infoWindow的交互性。

浏览器的当前位置 ( Browser's current location )

Let's spice things up by having our map pick our browser's current location. We will be using navigator which is a read-only property that returns a Geolocation object that gives Web content access to the location of the device.

让我们为地图选择浏览器的当前位置,为事情增添趣味。 我们将使用导航器 ,它是一个只读属性,它返回Geolocation对象,该对象使Web内容可以访问设备的位置。

In our src folder create a new file and name it Map.js and create a component named CurrentLocation this is where all our functionality to pick our browser's location will lie.

在我们的src文件夹中,创建一个新文件并将其命名为Map.js并创建一个名为CurrentLocation的组件,这是我们选择浏览器位置的所有功能所在。

We will begin by adding some default props to our CurrentLocation component, since we will need to set the map with a center incase the current location is not provided.This is handled by the boolean prop centerAroundCurrentLocation

我们将首先在CurrentLocation组件中添加一些默认道具,因为在未提供当前位置的情况下,我们需要将地图设置为中心,这由布尔道具centerAroundCurrentLocation处理

import React from 'react';
import ReactDOM from 'react-dom';

const mapStyles = {
  map: {
    position: 'absolute',
    width: '100%',
    height: '100%'
  }
};

export class CurrentLocation extends React.Component {

[...]

}
export default CurrentLocation;

CurrentLocation.defaultProps = {
  zoom: 14,
  initialCenter: {
    lat: -1.2884,
    lng: 36.8233
  },
  centerAroundCurrentLocation: false,
  visible: true
};

Next, we need to make our component stateful,

接下来,我们需要使组件有状态,

[...]

export class CurrentLocation extends React.Component {
  constructor(props) {
    super(props);

    const { lat, lng } = this.props.initialCenter;
    this.state = {
      currentLocation: {
        lat: lat,
        lng: lng
      }
    };
  }

[...]

}

Let's also update our CurrentLocation component to cater for the instance when the Map is first loaded as we cannot solely depend upon the google API being always available, hence we need to check if it's loaded. And also check if the browser's current location is provided and recenter the map to it.

我们还要更新我们的CurrentLocation组件,以适应首次加载地图时的实例,因为我们不能仅依赖于始终可用的google API,因此我们需要检查它是否已加载。 还要检查是否提供了浏览器的当前位置,并将地图更新到该位置。

[...]

componentDidUpdate(prevProps, prevState) {
    if (prevProps.google !== this.props.google) {
      this.loadMap();
    }
    if (prevState.currentLocation !== this.state.currentLocation) {
      this.recenterMap();
    }
  }

[...]

Let's define the recenterMap() function which only gets called when the currentLocation in the component's state is updated and uses the .panTo() method on the google.maps.Map instance to change the center of the map.

让我们定义一个recenterMap()函数,该函数仅在组件状态下的currentLocation更新时才调用,并使用google.maps.Map实例上的.panTo()方法更改地图的中心。

[...]

 recenterMap() {
    const map = this.map;
    const current = this.state.currentLocation;

    const google = this.props.google;
    const maps = google.maps;

    if (map) {
      let center = new maps.LatLng(current.lat, current.lng);
      map.panTo(center);
    }
  }

[...]

Next, we need to handle the instance when the map has already loaded.This will be handled by the componentDidMount() Lifecycle method which will set a call back to fetch the current location.

接下来,我们需要在地图已经加载时处理实例,这将由componentDidMount() Lifecycle方法处理,该方法将设置回叫以获取当前位置。

[...]

 componentDidMount() {
    if (this.props.centerAroundCurrentLocation) {
      if (navigator && navigator.geolocation) {
        navigator.geolocation.getCurrentPosition(pos => {
          const coords = pos.coords;
          this.setState({
            currentLocation: {
              lat: coords.latitude,
              lng: coords.longitude
            }
          });
        });
      }
    }
    this.loadMap();
  }

[...]

Notice the loadMap() function? Let's go on ahead and define it.

注意loadMap()函数吗? 让我们继续定义它。

[...]

loadMap() {
    if (this.props && this.props.google) {
      // checks if google is available
      const { google } = this.props;
      const maps = google.maps;

      const mapRef = this.refs.map;

      // reference to the actual DOM element
      const node = ReactDOM.findDOMNode(mapRef);

      let { zoom } = this.props;
      const { lat, lng } = this.state.currentLocation;
      const center = new maps.LatLng(lat, lng);
      const mapConfig = Object.assign(
        {},
        {
          center: center,
          zoom: zoom
        }
      );

      // maps.Map() is constructor that instantiates the map
      this.map = new maps.Map(node, mapConfig);
    }
  }

Basically, the loadMap() function is only called after the component has been rendered and grabs a reference to the DOM component to where we want our map to be placed.

基本上,仅在呈现组件之后才调用loadMap()函数,并获取对DOM组件的引用,该引用指向我们要放置地图的位置。

Our CurrentLocation component is almost looking up, But we need to ensure that our previous Marker picks our currenct location ie the browsers current location and so we need to introduce Parent-Child concept through the renderChildren() method which will be responsible for actually calling the method on the child component.

我们的CurrentLocation组件几乎要查找,但是我们需要确保之前的标记选择了当前位置,即浏览器的当前位置,因此我们需要通过renderChildren()方法引入Parent-Child概念,该方法将负责实际调用子组件上的方法。

Read more about Parent-Child communication here

在这里阅读更多关于亲子沟通的信息

[...]

 renderChildren() {
    const { children } = this.props;

    if (!children) return;

    return React.Children.map(children, c => {
      if (!c) return;
      return React.cloneElement(c, {
        map: this.map,
        google: this.props.google,
        mapCenter: this.state.currentLocation
      });
    });
  }

[...]

And finally, let's add our render() method

最后,让我们添加render()方法

[...]

render() {
     const style = Object.assign({}, mapStyles.map);
    return (
      <div>
        <div style={style} ref="map">
          Loading map...
        </div>
        {this.renderChildren()}
      </div>
    );
  }

[...]

Lastly, before we wind up we need to update our MapContainer component to include our new changes. So let's change it to this

最后,在结束之前,我们需要更新MapContainer组件以包括我们的新更改。 所以我们将其更改为

import React, { Component } from 'react';
import { GoogleApiWrapper, InfoWindow, Marker } from 'google-maps-react';

import CurrentLocation from './Map';

export class MapContainer extends Component {
  state = {
    showingInfoWindow: false,
    activeMarker: {},
    selectedPlace: {}
  };

  onMarkerClick = (props, marker, e) =>
    this.setState({
      selectedPlace: props,
      activeMarker: marker,
      showingInfoWindow: true
    });

  onClose = props => {
    if (this.state.showingInfoWindow) {
      this.setState({
        showingInfoWindow: false,
        activeMarker: null
      });
    }
  };

  render() {
    return (
      <CurrentLocation
        centerAroundCurrentLocation
        google={this.props.google}
      >
        <Marker onClick={this.onMarkerClick} name={'current location'} />
        <InfoWindow
          marker={this.state.activeMarker}
          visible={this.state.showingInfoWindow}
          onClose={this.onClose}
        >
          <div>
            <h4>{this.state.selectedPlace.name}</h4>
          </div>
        </InfoWindow>
      </CurrentLocation>
    );
  }
}

export default GoogleApiWrapper({
  apiKey: 'YOUR_GOOGLE_API_KEY_GOES_HERE'
})(MapContainer);

Run your app; heading over to our browser, our map should first load with our initialCenter then reload to pick our browser's current location with the marker positioned to this location and Voilà we are done.

运行您的应用; 转到浏览器,我们的地图应首先加载我们的initialCenter然后重新加载以选择浏览器的当前位置,并将标记定位到该位置,然后完成操作。

currentLocation.png

结论 ( Conclusion )

In this article we've been able to load our google maps React component, add a marker and have an infoWindow onto it and also have the map pick our current location. While we did not dive into adding more functionalities to our map such as, having polylines and polygons or adding event listeners, I highly recommend that you look into them

在本文中,我们已经能够加载Google Maps React组件,添加标记并在其上添加一个infoWindow,还可以让地图选择我们的当前位置。 虽然我们并未考虑向地图添加更多功能,例如具有折线和多边形或添加事件侦听器,但我强烈建议您调查一下它们

翻译自: https://scotch.io/tutorials/react-apps-with-the-google-maps-api-and-google-maps-react

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值